From d02eff00d9134e6150cf174cd5f92ad127a7cd5e Mon Sep 17 00:00:00 2001 From: jimmystar Date: Fri, 6 Sep 2013 16:31:21 +0800 Subject: [PATCH 001/116] Update cocos2d_specifics.cpp fix bug about scheduler, if this value is -1, it will work all right in Emulator, but run error in real device, just call one time. --- .../javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id index 9edcd1b1c0..09fa749af6 100644 --- a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id +++ b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id @@ -1 +1 @@ -cbe012e3979f31ec4001d6a0b65ba46823b497d7 \ No newline at end of file +0850425d8b210a393b8ae220cfd456f4e7907f37 \ No newline at end of file From 357466bab2bb360e4430f29cd7de158def157f78 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Mon, 9 Sep 2013 10:20:32 +0800 Subject: [PATCH 002/116] issue #2768:Add Armature lua binding and releated test samples --- extensions/cocos-ext.h | 7 + .../luaScript/ExtensionTest/ArmatureTest.lua | 815 ++++++++++++++++++ .../luaScript/ExtensionTest/ExtensionTest.lua | 44 +- .../project.pbxproj.REMOVED.git-id | 2 +- .../lua_cocos2dx_extension_manual.cpp | 97 +++ tools/tolua/cocos2dx_extension.ini | 17 +- 6 files changed, 975 insertions(+), 7 deletions(-) create mode 100644 samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua diff --git a/extensions/cocos-ext.h b/extensions/cocos-ext.h index 716f269065..552fe8dc6d 100644 --- a/extensions/cocos-ext.h +++ b/extensions/cocos-ext.h @@ -56,4 +56,11 @@ #include "CCDeprecated-ext.h" +#include "CCArmature/CCArmature.h" +#include "CCArmature/animation/CCArmatureAnimation.h" +#include "CCArmature/display/CCSkin.h" +#include "CCArmature/CCBone.h" +#include "CCArmature/utils/CCArmatureDataManager.h" +#include "CCArmature/datas/CCDatas.h" + #endif /* __COCOS2D_EXT_H__ */ diff --git a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua new file mode 100644 index 0000000000..3e7fbaac2e --- /dev/null +++ b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua @@ -0,0 +1,815 @@ +local itemTagBasic = 1000 +local winSize = cc.Director:getInstance():getWinSize() +local scheduler = cc.Director:getInstance():getScheduler() +local ArmatureTestIndex = +{ + TEST_COCOSTUDIO_WITH_SKELETON = 1, + TEST_COCOSTUDIO_WITHOUT_SKELETON = 2, + TEST_DRAGON_BONES_2_0 = 3, + TEST_PERFORMANCE = 4, + TEST_CHANGE_ZORDER = 5, + TEST_ANIMATION_EVENT = 6, + TEST_PARTICLE_DISPLAY = 7, + TEST_USE_DIFFERENT_PICTURE = 8, + TEST_BOUDINGBOX = 9, + TEST_ANCHORPOINT = 10, + TEST_ARMATURE_NESTING = 11, +} +local armatureSceneIdx = ArmatureTestIndex.TEST_COCOSTUDIO_WITH_SKELETON + +local ArmatureTestScene = class("ArmatureTestScene") +ArmatureTestScene.__index = ArmatureTestScene + +function ArmatureTestScene.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, ArmatureTestScene) + return target +end + +function ArmatureTestScene:runThisTest() + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/TestBone0.png", "armature/TestBone0.plist", "armature/TestBone.json") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/Cowboy0.png", "armature/Cowboy0.plist", "armature/Cowboy.json") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/knight.png", "armature/knight.plist", "armature/knight.xml") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/weapon.png", "armature/weapon.plist", "armature/weapon.xml") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/robot.png", "armature/robot.plist", "armature/robot.xml") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/cyborg.png", "armature/cyborg.plist", "armature/cyborg.xml") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/Dragon.png", "armature/Dragon.plist", "armature/Dragon.xml") + + armatureSceneIdx = ArmatureTestIndex.TEST_COCOSTUDIO_WITH_SKELETON + self:addChild(restartArmatureTest()) +end + +function ArmatureTestScene.create() + local scene = ArmatureTestScene.extend(cc.Scene:create()) + local bg = cc.Sprite:create("armature/bg.jpg") + bg:setPosition(VisibleRect:center()) + + local scaleX = VisibleRect:getVisibleRect().width / bg:getContentSize().width + local scaleY = VisibleRect:getVisibleRect().height / bg:getContentSize().height + + bg:setScaleX(scaleX) + bg:setScaleY(scaleY) + + scene:addChild(bg) + return scene +end + +function ArmatureTestScene.toMainMenuCallback() + cc.ArmatureDataManager:purgeArmatureSystem() +end + +local ArmatureTestLayer = class("ArmatureTestLayer") +ArmatureTestLayer.__index = ArmatureTestLayer + +function ArmatureTestLayer:onEnter() + +end + +function ArmatureTestLayer.title(idx) + if ArmatureTestIndex.TEST_COCOSTUDIO_WITH_SKELETON == idx then + return "Test Export From CocoStudio With Skeleton Effect" + elseif ArmatureTestIndex.TEST_COCOSTUDIO_WITHOUT_SKELETON == idx then + return "Test Export From CocoStudio Without Skeleton Effect" + elseif ArmatureTestIndex.TEST_DRAGON_BONES_2_0 == idx then + return "Test Export From DragonBones version 2.0" + elseif ArmatureTestIndex.TEST_PERFORMANCE == idx then + return "Test Performance" + elseif ArmatureTestIndex.TEST_CHANGE_ZORDER == idx then + return "Test Change ZOrder Of Different Armature" + elseif ArmatureTestIndex.TEST_ANIMATION_EVENT == idx then + return "Test Armature Animation Event" + elseif ArmatureTestIndex.TEST_PARTICLE_DISPLAY == idx then + return "Test Particle Display" + elseif ArmatureTestIndex.TEST_USE_DIFFERENT_PICTURE == idx then + return "Test One Armature Use Different Picture" + elseif ArmatureTestIndex.TEST_BOUDINGBOX == idx then + return "Test BoundingBox" + elseif ArmatureTestIndex.TEST_ANCHORPOINT == idx then + return "Test Set AnchorPoint" + elseif ArmatureTestIndex.TEST_ARMATURE_NESTING == idx then + return "Test Armature Nesting" + end +end + +function ArmatureTestLayer.subTitle(idx) + if ArmatureTestIndex.TEST_PERFORMANCE == idx then + return "Current Armature Count : " + elseif ArmatureTestIndex.TEST_PARTICLE_DISPLAY == idx then + return "Touch to change animation" + elseif ArmatureTestIndex.TEST_USE_DIFFERENT_PICTURE == idx then + return "weapon and armature are in different picture" + else + return "" + end +end + +function ArmatureTestLayer.create() + local layer = ArmatureTestLayer.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +function ArmatureTestLayer.backCallback() + local newScene = ArmatureTestScene.create() + newScene:addChild(backArmatureTest()) + cc.Director:getInstance():replaceScene(newScene) +end + +function ArmatureTestLayer.restartCallback() + local newScene = ArmatureTestScene.create() + newScene:addChild(restartArmatureTest()) + cc.Director:getInstance():replaceScene(newScene) +end + +function ArmatureTestLayer.nextCallback() + local newScene = ArmatureTestScene.create() + newScene:addChild(nextArmatureTest()) + cc.Director:getInstance():replaceScene(newScene) +end + +function ArmatureTestLayer:createMenu() + local menu = cc.Menu:create() + + local item1 = cc.MenuItemImage:create(s_pPathB1, s_pPathB2) + item1:registerScriptTapHandler(self.backCallback) + menu:addChild(item1,itemTagBasic) + local item2 = cc.MenuItemImage:create(s_pPathR1, s_pPathR2) + item2:registerScriptTapHandler(self.restartCallback) + menu:addChild(item2,itemTagBasic) + local item3 = cc.MenuItemImage:create(s_pPathF1, s_pPathF2) + menu:addChild(item3,itemTagBasic) + item3:registerScriptTapHandler(self.nextCallback) + + local size = cc.Director:getInstance():getWinSize() + item1:setPosition(cc.p(size.width / 2 - item2:getContentSize().width * 2, item2:getContentSize().height / 2)) + item2:setPosition(cc.p(size.width / 2, item2:getContentSize().height / 2)) + item3:setPosition(cc.p(size.width / 2 + item2:getContentSize().width * 2, item2:getContentSize().height / 2)) + + menu:setPosition(cc.p(0, 0)) + + self:addChild(menu) +end + +function ArmatureTestLayer.toExtensionMenu() + local scene = ExtensionsTestMain() + if scene ~= nil then + cc.Director:getInstance():replaceScene(scene) + end +end + +function ArmatureTestLayer:createToExtensionMenu() + cc.MenuItemFont:setFontName("Arial") + cc.MenuItemFont:setFontSize(24) + local menuItemFont = cc.MenuItemFont:create("Back") + menuItemFont:setPosition(cc.p(VisibleRect:rightBottom().x - 50, VisibleRect:rightBottom().y + 25)) + menuItemFont:registerScriptTapHandler(ArmatureTestLayer.toExtensionMenu) + + local backMenu = cc.Menu:create() + backMenu:addChild(menuItemFont) + backMenu:setPosition(cc.p(0, 0)) + self:addChild(backMenu,10) +end + +function ArmatureTestLayer:creatTitleAndSubTitle(idx) + local title = cc.LabelTTF:create(ArmatureTestLayer.title(idx),"Arial",18) + title:setColor(cc.c3b(0,0,0)) + self:addChild(title, 1, 10000) + title:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 30)) + local subTitle = nil + if "" ~= ArmatureTestLayer.subTitle(idx) then + local subTitle = cc.LabelTTF:create(ArmatureTestLayer.subTitle(idx), "Arial", 18) + subTitle:setColor(cc.c3b(0,0,0)) + self:addChild(subTitle, 1, 10001) + subTitle:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 60) ) + end +end + +local TestCSWithSkeleton = class("TestCSWithSkeleton",ArmatureTestLayer) +TestCSWithSkeleton.__index = TestCSWithSkeleton + +function TestCSWithSkeleton.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestCSWithSkeleton) + return target +end + +function TestCSWithSkeleton:onEnter() + local armature = cc.Armature:create("Cowboy") + armature:getAnimation():playByIndex(0) + armature:setScale(0.2) + armature:setAnchorPoint(cc.p(0.5, 0.5)) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2)) + self:addChild(armature) +end + +function TestCSWithSkeleton.create() + local layer = TestCSWithSkeleton.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local TestCSWithoutSkeleton = class("TestCSWithoutSkeleton",ArmatureTestLayer) +TestCSWithoutSkeleton.__index = TestCSWithoutSkeleton + +function TestCSWithoutSkeleton.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestCSWithoutSkeleton) + return target +end + +function TestCSWithoutSkeleton:onEnter() + local armature = cc.Armature:create("TestBone") + armature:getAnimation():playByIndex(0) + armature:setScale(0.2) + armature:setAnchorPoint(cc.p(0.5, 0.5)) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2)) + self:addChild(armature) +end + +function TestCSWithoutSkeleton.create() + local layer = TestCSWithoutSkeleton.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + return layer +end + +local TestDragonBones20 = class("TestDragonBones20",ArmatureTestLayer) +TestDragonBones20.__index = TestDragonBones20 + +function TestDragonBones20.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestDragonBones20) + return target +end + +function TestDragonBones20:onEnter() + local armature = cc.Armature:create("Dragon") + armature:getAnimation():playByIndex(1) + armature:getAnimation():setAnimationScale(0.4) + armature:setScale(0.6) + armature:setAnchorPoint(cc.p(0.5, 0.5)) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2)) + self:addChild(armature) +end + +function TestDragonBones20.create() + local layer = TestDragonBones20.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + return layer +end + +local TestPerformance = class("TestPerformance",ArmatureTestLayer) +TestPerformance.__index = TestPerformance +TestPerformance.armatureCount = 0 +TestPerformance.times = 0 +TestPerformance.testPerformanceEntry = 0 +TestPerformance.selfLayer = nil + +function TestPerformance.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestPerformance) + return target +end + +function TestPerformance.update(delta) + TestPerformance.times = TestPerformance.times + delta + if TestPerformance.times > 0.25 then + TestPerformance.time = 0 + local armature = cc.Armature:create("Knight_f/Knight") + armature:getAnimation():playByIndex(0) + armature:setPosition(cc.p(50 + TestPerformance.armatureCount * 5, winSize.height / 2)) + armature:setScale(0.6) + TestPerformance.armatureCount = TestPerformance.armatureCount + 1 + TestPerformance.selfLayer:addChild(armature,TestPerformance.armatureCount) + + local subTitle = tolua.cast(TestPerformance.selfLayer:getChildByTag(10001),"LabelTTF") + if nil ~= subTitle then + local info = ArmatureTestLayer.subTitle(ArmatureTestIndex.TEST_PERFORMANCE) .. TestPerformance.armatureCount + subTitle:setString(info) + end + end +end + +function TestPerformance.onEnterOrExit(tag) + if tag == "enter" then + TestPerformance.testPerformanceEntry = scheduler:scheduleScriptFunc(TestPerformance.update, 0.0, false) + elseif tag == "exit" then + scheduler:unscheduleScriptEntry(TestPerformance.testPerformanceEntry) + end +end + +function TestPerformance:onEnter() + TestPerformance.armatureCount = 0 + TestPerformance.times = 0 + TestPerformance.selfLayer = nil + self:registerScriptHandler(self.onEnterOrExit) +end + +function TestPerformance.create() + local layer = TestPerformance.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + TestPerformance.selfLayer = layer + end + return layer +end + +local TestCSWithoutSkeleton = class("TestCSWithoutSkeleton",ArmatureTestLayer) +TestCSWithoutSkeleton.__index = TestCSWithoutSkeleton + +function TestCSWithoutSkeleton.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestCSWithoutSkeleton) + return target +end + +function TestCSWithoutSkeleton:onEnter() + local armature = cc.Armature:create("TestBone") + armature:getAnimation():playByIndex(0) + armature:setScale(0.2) + armature:setAnchorPoint(cc.p(0.5, 0.5)) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2)) + self:addChild(armature) +end + +function TestCSWithoutSkeleton.create() + local layer = TestCSWithoutSkeleton.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + return layer +end + +local TestChangeZorder = class("TestChangeZorder",ArmatureTestLayer) +TestChangeZorder.__index = TestChangeZorder +TestChangeZorder.currentTag = -1 + +function TestChangeZorder.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestChangeZorder) + return target +end + +function TestChangeZorder:onEnter() + self.currentTag = -1 + + local armature = cc.Armature:create("Knight_f/Knight") + armature:getAnimation():playByIndex(0) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2 - 100 )) + armature:setScale(0.6) + self.currentTag = self.currentTag + 1 + self:addChild(armature, self.currentTag, self.currentTag) + + armature = cc.Armature:create("TestBone") + armature:getAnimation():playByIndex(0) + armature:setScale(0.24) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2 - 100)) + self.currentTag = self.currentTag + 1 + self:addChild(armature, self.currentTag, self.currentTag) + + armature = cc.Armature:create("Dragon") + armature:getAnimation():playByIndex(0) + armature:setPosition(cc.p(winSize.width / 2, winSize.height / 2 - 100)) + armature:setScale(0.6) + self.currentTag = self.currentTag + 1 + self:addChild(armature, self.currentTag, self.currentTag) + + local function changeZorder(dt) + local node = self:getChildByTag(self.currentTag) + node:setZOrder(math.random(0,1) * 3) + self.currentTag = (self.currentTag + 1) % 3 + end + + schedule(self,changeZorder, 1) +end + +function TestChangeZorder.create() + local layer = TestChangeZorder.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + return layer +end + +--UNDO callback +local TestAnimationEvent = class("TestAnimationEvent",ArmatureTestLayer) +TestAnimationEvent.__index = TestAnimationEvent + +function TestAnimationEvent.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestAnimationEvent) + return target +end + +function TestAnimationEvent:onEnter() + local armature = cc.Armature:create("Cowboy") + armature:getAnimation():play("Fire") + armature:setScaleX(-0.24) + armature:setScaleY(0.24) + armature:setPosition(cc.p(VisibleRect:left().x + 50, VisibleRect:left().y)) + --armature:getAnimation()->MovementEventSignal.connect(this, &TestAnimationEvent::animationEvent) + self:addChild(armature) +end + +function TestAnimationEvent.create() + local layer = TestAnimationEvent.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + return layer +end + +local TestParticleDisplay = class("TestParticleDisplay",ArmatureTestLayer) +TestParticleDisplay.__index = TestParticleDisplay +TestParticleDisplay.animationID = 0 +TestParticleDisplay.armature = nil + +function TestParticleDisplay.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestParticleDisplay) + return target +end + +function TestParticleDisplay:onEnter() + self:setTouchEnabled(true) + self.animationID = 0 + + self.armature = cc.Armature:create("robot") + self.armature:getAnimation():playByIndex(0) + self.armature:setPosition(VisibleRect:center()) + self.armature:setScale(0.48) + self:addChild(self.armature) + + local displayData = cc.ParticleDisplayData:create() + displayData:setParam("Particles/SmallSun.plist") + + local bone = cc.Bone:create("p1") + bone:addDisplay(displayData, 0) + bone:changeDisplayByIndex(0, true) + bone:setIgnoreMovementBoneData(true) + bone:setZOrder(100) + bone:setScale(1.2) + self.armature:addBone(bone, "bady-a3") + + bone = cc.Bone:create("p2") + bone:addDisplay(displayData, 0) + bone:changeDisplayByIndex(0, true) + bone:setIgnoreMovementBoneData(true) + bone:setZOrder(100) + bone:setScale(1.2) + self.armature:addBone(bone, "bady-a30") + + local function onTouchBegan(x, y) + self.animationID = (self.animationID + 1) % self.armature:getAnimation():getMovementCount() + self.armature:getAnimation():playByIndex(self.animationID) + return false + end + + local function onTouch(eventType, x, y) + if eventType == "began" then + return onTouchBegan(x,y) + end + end + + self:registerScriptTouchHandler(onTouch) +end + +function TestParticleDisplay.create() + local layer = TestParticleDisplay.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local TestUseMutiplePicture = class("TestUseMutiplePicture",ArmatureTestLayer) +TestUseMutiplePicture.__index = TestUseMutiplePicture +TestUseMutiplePicture.displayIndex = 0 +TestUseMutiplePicture.armature = nil + +function TestUseMutiplePicture.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestUseMutiplePicture) + return target +end + +function TestUseMutiplePicture:onEnter() + self:setTouchEnabled(true) + self.displayIndex = 1 + + self.armature = cc.Armature:create("Knight_f/Knight") + self.armature:getAnimation():playByIndex(0) + self.armature:setPosition(cc.p(VisibleRect:left().x + 70, VisibleRect:left().y)) + self.armature:setScale(1.2) + self:addChild(self.armature) + + local weapon = + { + "weapon_f-sword.png", + "weapon_f-sword2.png", + "weapon_f-sword3.png", + "weapon_f-sword4.png", + "weapon_f-sword5.png", + "weapon_f-knife.png", + "weapon_f-hammer.png", + }; + + local spriteDisplayData = cc.SpriteDisplayData:create() + local i = 1 + for i = 1,table.getn(weapon) do + spriteDisplayData:setParam(weapon[i]) + self.armature:getBone("weapon"):addDisplay(spriteDisplayData, i - 1) + end + + local function onTouchBegan(x, y) + self.displayIndex = (self.displayIndex + 1) % (table.getn(weapon) - 1) + self.armature:getBone("weapon"):changeDisplayByIndex(self.displayIndex, true) + return false + end + + local function onTouch(eventType, x, y) + if eventType == "began" then + return onTouchBegan(x,y) + end + end + + self:registerScriptTouchHandler(onTouch) +end + +function TestUseMutiplePicture.create() + local layer = TestUseMutiplePicture.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local TestBoundingBox = class("TestBoundingBox",ArmatureTestLayer) +TestBoundingBox.__index = TestBoundingBox + +function TestBoundingBox.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestBoundingBox) + return target +end + +function TestBoundingBox:onEnter() + local armature = cc.Armature:create("Cowboy") + armature:getAnimation():playByIndex(0) + armature:setPosition(VisibleRect:center()) + armature:setScale(0.2) + self:addChild(armature) +end + +function TestBoundingBox.create() + local layer = TestBoundingBox.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local TestAnchorPoint = class("TestAnchorPoint",ArmatureTestLayer) +TestAnchorPoint.__index = TestAnchorPoint + +function TestAnchorPoint.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestAnchorPoint) + return target +end + +function TestAnchorPoint:onEnter() + local i = 1 + for i = 1 , 5 do + local armature = cc.Armature:create("Cowboy") + armature:getAnimation():playByIndex(0); + armature:setPosition(VisibleRect:center()) + armature:setScale(0.2) + self:addChild(armature, 0, i - 1) + end + + self:getChildByTag(0):setAnchorPoint(cc.p(0,0)) + self:getChildByTag(1):setAnchorPoint(cc.p(0,1)) + self:getChildByTag(2):setAnchorPoint(cc.p(1,0)) + self:getChildByTag(3):setAnchorPoint(cc.p(1,1)) + self:getChildByTag(4):setAnchorPoint(cc.p(0.5,0.5)) +end + +function TestAnchorPoint.create() + local layer = TestAnchorPoint.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local TestArmatureNesting = class("TestArmatureNesting",ArmatureTestLayer) +TestArmatureNesting.__index = TestArmatureNesting +TestArmatureNesting.weaponIndex = 0 +TestArmatureNesting.armature = nil + +function TestArmatureNesting.extend(target) + local t = tolua.getpeer(target) + if not t then + t = {} + tolua.setpeer(target, t) + end + setmetatable(t, TestArmatureNesting) + return target +end + +function TestArmatureNesting:onEnter() + self:setTouchEnabled(true) + self.weaponIndex = 0 + + self.armature = cc.Armature:create("cyborg") + self.armature:getAnimation():playByIndex(1) + self.armature:setPosition(VisibleRect:center()) + self.armature:setScale(1.2) + self.armature:getAnimation():setAnimationScale(0.4) + self:addChild(self.armature) + + local function onTouchBegan(x, y) + self.weaponIndex = (self.weaponIndex + 1) % 4 + self.armature:getBone("armInside"):getChildArmature():getAnimation():playByIndex(self.weaponIndex) + self.armature:getBone("armOutside"):getChildArmature():getAnimation():playByIndex(self.weaponIndex) + return false + end + + local function onTouch(eventType, x, y) + if eventType == "began" then + return onTouchBegan(x,y) + end + end + + self:registerScriptTouchHandler(onTouch) +end + +function TestArmatureNesting.create() + local layer = TestArmatureNesting.extend(cc.Layer:create()) + + if nil ~= layer then + layer:createMenu() + layer:createToExtensionMenu() + layer:onEnter() + layer:creatTitleAndSubTitle(armatureSceneIdx) + end + + return layer +end + +local armatureSceneArr = +{ + TestCSWithSkeleton.create, + TestCSWithoutSkeleton.create, + TestDragonBones20.create, + TestPerformance.create, + TestChangeZorder.create, + TestAnimationEvent.create, + TestParticleDisplay.create, + TestUseMutiplePicture.create, + TestBoundingBox.create, + TestAnchorPoint.create, + TestArmatureNesting.create, +} + +function nextArmatureTest() + armatureSceneIdx = armatureSceneIdx + 1 + armatureSceneIdx = armatureSceneIdx % table.getn(armatureSceneArr) + if 0 == armatureSceneIdx then + armatureSceneIdx = table.getn(armatureSceneArr) + end + return armatureSceneArr[armatureSceneIdx]() +end + +function backArmatureTest() + armatureSceneIdx = armatureSceneIdx - 1 + if armatureSceneIdx <= 0 then + armatureSceneIdx = armatureSceneIdx + table.getn(armatureSceneArr) + end + + return armatureSceneArr[armatureSceneIdx]() +end + +function restartArmatureTest() + return armatureSceneArr[armatureSceneIdx]() +end + +local function addFileInfo() + +end + +function runArmatureTest() + local newScene = ArmatureTestScene.create() + newScene:runThisTest() + return newScene +end \ No newline at end of file diff --git a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua index 0fd38615ee..0197b6ec4e 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua @@ -1,5 +1,6 @@ require "luaScript/ExtensionTest/CocosBuilderTest" require "luaScript/ExtensionTest/WebProxyTest" +require "luaScript/ExtensionTest/ArmatureTest" local LINE_SPACE = 40 local kItemTagBasic = 1000 @@ -13,7 +14,8 @@ local ExtensionTestEnum = TEST_EDITBOX = 4, TEST_TABLEVIEW = 5, TEST_SCROLLVIEW = 6, - TEST_MAX_COUNT = 7, + TEST_ARMATURE = 7, + TEST_MAX_COUNT = 8, } local testsName = @@ -25,6 +27,7 @@ local testsName = "EditBoxTest", "TableViewTest", "ScrollViewTest", + "ArmatureTest", } @@ -1190,6 +1193,7 @@ local CreateExtensionsTestTable = runEditBoxTest, runTableViewTest, runScrollViewTest, + runArmatureTest, } @@ -1240,6 +1244,44 @@ local function ExtensionsMainLayer() layer:addChild(menu) + -- handling touch events + local beginPos = {x = 0, y = 0} + local function onTouchBegan(x, y) + beginPos = {x = x, y = y} + return true + end + + local function onTouchMoved(x, y) + local nMoveY = y - beginPos.y + local curPosx, curPosy = menu:getPosition() + local nextPosy = curPosy + nMoveY + local winSize = cc.Director:getInstance():getWinSize() + if nextPosy < 0 then + menu:setPosition(0, 0) + return + end + + if nextPosy > ((ExtensionTestEnum.TEST_MAX_COUNT + 1) * LINE_SPACE - winSize.height) then + menu:setPosition(0, ((ExtensionTestEnum.TEST_MAX_COUNT + 1) * LINE_SPACE - winSize.height)) + return + end + + menu:setPosition(curPosx, nextPosy) + beginPos = {x = x, y = y} + end + + local function onTouch(eventType, x, y) + if eventType == "began" then + return onTouchBegan(x, y) + elseif eventType == "moved" then + return onTouchMoved(x, y) + end + end + + layer:setTouchEnabled(true) + + layer:registerScriptTouchHandler(onTouch) + return layer end diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index ef847642e4..b1bce20777 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -a9fdccd58c6cf8ce3cb5d00ea294ef9ff216d439 \ No newline at end of file +2412d119adc08bbb78bebb1bc2e66d0d40b8b146 \ No newline at end of file diff --git a/scripting/lua/cocos2dx_support/lua_cocos2dx_extension_manual.cpp b/scripting/lua/cocos2dx_support/lua_cocos2dx_extension_manual.cpp index 93cf6ce837..fa9416c93e 100644 --- a/scripting/lua/cocos2dx_support/lua_cocos2dx_extension_manual.cpp +++ b/scripting/lua/cocos2dx_support/lua_cocos2dx_extension_manual.cpp @@ -1329,6 +1329,102 @@ static void extendTableView(lua_State* L) } } +static int lua_cocos2dx_extension_Bone_setIgnoreMovementBoneData(lua_State* L) +{ + if (nullptr == L) + return 0; + + int argc = 0; + armature::Bone* self = nullptr; + +#if COCOS2D_DEBUG >= 1 + tolua_Error tolua_err; + if (!tolua_isusertype(L,1,"Bone",0,&tolua_err)) goto tolua_lerror; +#endif + + self = static_cast(tolua_tousertype(L,1,0)); + +#if COCOS2D_DEBUG >= 1 + if (nullptr == self) { + tolua_error(L,"invalid 'self' in function 'lua_cocos2dx_extension_Bone_setIgnoreMovementBoneData'\n", NULL); + return 0; + } +#endif + + argc = lua_gettop(L) - 1; + + if (1 == argc) + { +#if COCOS2D_DEBUG >= 1 + if (!tolua_isboolean(L, 2, 0, &tolua_err)) + goto tolua_lerror; +#endif + bool ignore = (bool)tolua_toboolean(L, 2, 0); + self->setIgnoreMovementBoneData(ignore); + return 0; + } + + CCLOG("'setIgnoreMovementBoneData' function of Bone has wrong number of arguments: %d, was expecting %d\n", argc, 0); + return 0; + +#if COCOS2D_DEBUG >= 1 +tolua_lerror: + tolua_error(L,"#ferror in function 'setIgnoreMovementBoneData'.",&tolua_err); + return 0; +#endif +} + +static int lua_cocos2dx_extension_Bone_getIgnoreMovementBoneData(lua_State* L) +{ + if (nullptr == L) + return 0; + + int argc = 0; + armature::Bone* self = nullptr; + +#if COCOS2D_DEBUG >= 1 + tolua_Error tolua_err; + if (!tolua_isusertype(L,1,"Bone",0,&tolua_err)) goto tolua_lerror; +#endif + + self = static_cast(tolua_tousertype(L,1,0)); + +#if COCOS2D_DEBUG >= 1 + if (nullptr == self) { + tolua_error(L,"invalid 'self' in function 'lua_cocos2dx_extension_Bone_getIgnoreMovementBoneData'\n", NULL); + return 0; + } +#endif + + argc = lua_gettop(L) - 1; + + if (0 == argc) + { + tolua_pushboolean(L, self->getIgnoreMovementBoneData()); + return 1; + } + + CCLOG("'getIgnoreMovementBoneData' function of Bone has wrong number of arguments: %d, was expecting %d\n", argc, 0); + return 0; + +#if COCOS2D_DEBUG >= 1 +tolua_lerror: + tolua_error(L,"#ferror in function 'getIgnoreMovementBoneData'.",&tolua_err); + return 0; +#endif +} + +static void extendBone(lua_State* L) +{ + lua_pushstring(L, "Bone"); + lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_istable(L,-1)) + { + tolua_function(L, "setIgnoreMovementBoneData", lua_cocos2dx_extension_Bone_setIgnoreMovementBoneData); + tolua_function(L, "getIgnoreMovementBoneData", lua_cocos2dx_extension_Bone_getIgnoreMovementBoneData); + } +} + int register_all_cocos2dx_extension_manual(lua_State* tolua_S) { extendScrollView(tolua_S); @@ -1337,5 +1433,6 @@ int register_all_cocos2dx_extension_manual(lua_State* tolua_S) extendCCBReader(tolua_S); extendCCBAnimationManager(tolua_S); extendTableView(tolua_S); + extendBone(tolua_S); return 0; } diff --git a/tools/tolua/cocos2dx_extension.ini b/tools/tolua/cocos2dx_extension.ini index 62ccd46dd3..5f35f20cbe 100644 --- a/tools/tolua/cocos2dx_extension.ini +++ b/tools/tolua/cocos2dx_extension.ini @@ -26,7 +26,7 @@ headers = %(cocosdir)s/extensions/cocos-ext.h # what classes to produce code for. You can use regular expressions here. When testing the regular # expression, it will be enclosed in "^$", like this: "^Menu*$". -classes = CCBReader.* CCBAnimationManager.* Scale9Sprite Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$ EditBox$ +classes = CCBReader.* CCBAnimationManager.* Scale9Sprite Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$ EditBox$ Armature ArmatureAnimation Skin Bone ArmatureDataManager \w+Data$ # what should we skip? in the format ClassName::[function function] # ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also @@ -45,9 +45,16 @@ skip = CCBReader::[^CCBReader$ addOwnerCallbackName isJSControlled readByte getC TableView::[create (g|s)etDataSource$ (g|s)etDelegate], Control::[removeHandleOfControlEvent addHandleOfControlEvent], ControlUtils::[*], - ControlSwitchSprite::[*] + ControlSwitchSprite::[*], + ArmatureDataManager::[CCArmatureDataManager ~CCArmatureDataManager], + Armature::[createBone updateBlendType getCPBody setCPBody (s|g)etBlendFunc], + Skin::[getSkinData setSkinData], + ArmatureAnimation::[updateHandler updateFrameData frameEvent], + Bone::[(s|g)etIgnoreMovementBoneData] -rename_functions = CCBReader::[getAnimationManager=getActionManager setAnimationManager=setActionManager] + +rename_functions = CCBReader::[getAnimationManager=getActionManager setAnimationManager=setActionManager], + ArmatureDataManager::[sharedArmatureDataManager=getInstance] rename_classes = CCBReader::_Reader, CCBAnimationManager::AnimationManager @@ -59,11 +66,11 @@ remove_prefix = classes_have_no_parents = # base classes which will be skipped when their sub-classes found them. -base_classes_to_skip = Object +base_classes_to_skip = Object ProcessBase # classes that create no constructor # Set is special and we will use a hand-written constructor -abstract_classes = +abstract_classes = ArmatureDataManager # Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'. script_control_cpp = no From 95831eb70f46df1ed75d581f51097f634bcacaa9 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Sat, 14 Sep 2013 20:00:26 +0800 Subject: [PATCH 003/116] issue #2768:Add a newline --- .../TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua index 3e7fbaac2e..7374719740 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua @@ -812,4 +812,4 @@ function runArmatureTest() local newScene = ArmatureTestScene.create() newScene:runThisTest() return newScene -end \ No newline at end of file +end From 1e093868c8ff47a9bfefbf6576391a1c1e14e3dd Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Sun, 15 Sep 2013 09:53:08 +0800 Subject: [PATCH 004/116] issue #2768:Modify testlua and hellolua sample's linux mayflies. --- samples/Lua/HelloLua/proj.linux/Makefile | 2 +- samples/Lua/TestLua/proj.linux/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Lua/HelloLua/proj.linux/Makefile b/samples/Lua/HelloLua/proj.linux/Makefile index f0b63ea010..9c80a175dd 100644 --- a/samples/Lua/HelloLua/proj.linux/Makefile +++ b/samples/Lua/HelloLua/proj.linux/Makefile @@ -10,7 +10,7 @@ INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ SOURCES = main.cpp ../Classes/AppDelegate.cpp SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -lextension -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so +COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so $(LIB_DIR)/libbox2d.so include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk diff --git a/samples/Lua/TestLua/proj.linux/Makefile b/samples/Lua/TestLua/proj.linux/Makefile index cb88cc9a93..6d73226774 100644 --- a/samples/Lua/TestLua/proj.linux/Makefile +++ b/samples/Lua/TestLua/proj.linux/Makefile @@ -9,7 +9,7 @@ INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ SOURCES = main.cpp ../Classes/AppDelegate.cpp SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so +COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so $(LIB_DIR)/libbox2d.so include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk From dbfd05ef779bab1aa898ab1a7791998430b971e4 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Sun, 29 Sep 2013 09:39:20 +0800 Subject: [PATCH 005/116] issue #2771: add tag and enable functions to physics classes --- .../CCScene.cpp | 2 +- cocos2dx/physics/CCPhysicsBody.cpp | 82 ++++++++++- cocos2dx/physics/CCPhysicsBody.h | 10 ++ cocos2dx/physics/CCPhysicsJoint.cpp | 17 +++ cocos2dx/physics/CCPhysicsJoint.h | 7 + cocos2dx/physics/CCPhysicsShape.cpp | 22 +++ cocos2dx/physics/CCPhysicsShape.h | 6 + cocos2dx/physics/CCPhysicsWorld.cpp | 127 +++++++++++++++--- cocos2dx/physics/CCPhysicsWorld.h | 10 +- .../physics/chipmunk/CCPhysicsShapeInfo.cpp | 8 +- 10 files changed, 260 insertions(+), 31 deletions(-) diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp index 36f2947dc6..0950fcd0a8 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp +++ b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp @@ -137,7 +137,7 @@ void Scene::addChildToPhysicsWorld(Node* child) if (sp->getPhysicsBody()) { - _physicsWorld->addChild(sp->getPhysicsBody()); + _physicsWorld->addBody(sp->getPhysicsBody()); } } }; diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index 3fb5d485b1..2c190eefdd 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -63,12 +63,14 @@ PhysicsBody::PhysicsBody() , _world(nullptr) , _info(nullptr) , _dynamic(false) +, _enable(true) , _massDefault(true) , _angularDampingDefault(true) , _mass(MASS_DEFAULT) , _area(0.0) , _density(DENSITY_DEFAULT) , _angularDamping(ANGULARDAMPING_DEFAULT) +, _tag(0) { } @@ -76,10 +78,7 @@ PhysicsBody::~PhysicsBody() { CC_SAFE_DELETE(_info); - for (auto it = _shapes.begin(); it != _shapes.end(); ++it) - { - delete *it; - } + removeAllShapes(); for (auto it = _joints.begin(); it != _joints.end(); ++it) { @@ -375,6 +374,81 @@ void PhysicsBody::setAngularDamping(float angularDamping) cpBodySetMoment(_info->body, _angularDamping); } +PhysicsShape* PhysicsBody::getShapeByTag(int tag) +{ + for (auto shape : _shapes) + { + if (shape->getTag() == tag) + { + return shape; + } + } + + return nullptr; +} + +void PhysicsBody::removeShapeByTag(int tag) +{ + for (auto shape : _shapes) + { + if (shape->getTag() == tag) + { + removeShape(shape); + return; + } + } +} + +void PhysicsBody::removeShape(PhysicsShape* shape) +{ + auto it = std::find(_shapes.begin(), _shapes.end(), shape); + + if (it != _shapes.end()) + { + if (_world) + { + _world->removeShape(shape); + } + + _shapes.erase(it); + delete shape; + } +} + +void PhysicsBody::removeAllShapes() +{ + for (auto shape : _shapes) + { + if (_world) + { + _world->removeShape(shape); + } + + delete shape; + } + + _shapes.clear(); +} + +void PhysicsBody::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (_world) + { + if (enable) + { + _world->addBody(this); + }else + { + _world->removeBody(this); + } + } + } +} + //Clonable* PhysicsBody::clone() const //{ // PhysicsBody* body = new PhysicsBody(); diff --git a/cocos2dx/physics/CCPhysicsBody.h b/cocos2dx/physics/CCPhysicsBody.h index 515366e64e..94d30f8b63 100644 --- a/cocos2dx/physics/CCPhysicsBody.h +++ b/cocos2dx/physics/CCPhysicsBody.h @@ -145,10 +145,12 @@ public: * @brief get the first body shapes. */ inline PhysicsShape* getShape() { return _shapes.size() >= 1 ? _shapes.front() : nullptr; } + PhysicsShape* getShapeByTag(int tag); /* * @brief remove a shape from body */ void removeShape(PhysicsShape* shape); + void removeShapeByTag(int tag); /* * @brief remove all shapes */ @@ -215,6 +217,12 @@ public: //virtual Clonable* clone() const override; + inline bool isEnable() { return _enable; } + void setEnable(bool enable); + + inline int getTag() { return _tag; } + inline void setTag(int tag) { _tag = tag; } + protected: bool init(); @@ -235,12 +243,14 @@ protected: PhysicsWorld* _world; PhysicsBodyInfo* _info; bool _dynamic; + bool _enable; bool _massDefault; bool _angularDampingDefault; float _mass; float _area; float _density; float _angularDamping; + int _tag; int _categoryBitmask; int _contactTestBitmask; diff --git a/cocos2dx/physics/CCPhysicsJoint.cpp b/cocos2dx/physics/CCPhysicsJoint.cpp index 3e60d246ab..63b6ac052e 100644 --- a/cocos2dx/physics/CCPhysicsJoint.cpp +++ b/cocos2dx/physics/CCPhysicsJoint.cpp @@ -46,6 +46,8 @@ PhysicsJoint::PhysicsJoint() : _bodyA(nullptr) , _bodyB(nullptr) , _info(nullptr) +, _enable(false) +, _tag(0) { } @@ -79,6 +81,21 @@ bool PhysicsJoint::init(cocos2d::PhysicsBody *a, cocos2d::PhysicsBody *b) return false; } +void PhysicsJoint::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (enable) + { + + }else + { + + } + } +} PhysicsJointPin::PhysicsJointPin() { diff --git a/cocos2dx/physics/CCPhysicsJoint.h b/cocos2dx/physics/CCPhysicsJoint.h index 854963049d..73383c39b6 100644 --- a/cocos2dx/physics/CCPhysicsJoint.h +++ b/cocos2dx/physics/CCPhysicsJoint.h @@ -49,6 +49,10 @@ protected: public: PhysicsBody* getBodyA() { return _bodyA; } PhysicsBody* getBodyB() { return _bodyB; } + inline int getTag() { return _tag; } + inline void setTag(int tag) { _tag = tag; } + inline bool isEnable() { return _enable; } + void setEnable(bool enable); protected: bool init(PhysicsBody* a, PhysicsBody* b); @@ -62,8 +66,11 @@ protected: PhysicsBody* _bodyA; PhysicsBody* _bodyB; PhysicsJointInfo* _info; + bool _enable; + int _tag; friend class PhysicsBody; + friend class PhysicsWorld; }; /* diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index e98dff0b5c..1ce4cbb3b5 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -32,6 +32,7 @@ #endif #include "CCPhysicsBody.h" +#include "CCPhysicsWorld.h" #include "chipmunk/CCPhysicsBodyInfo.h" #include "Box2D/CCPhysicsBodyInfo.h" @@ -45,6 +46,8 @@ PhysicsShape::PhysicsShape() : _body(nullptr) , _info(nullptr) , _type(Type::UNKNOWN) +, _tag(0) +, _enable(true) { } @@ -68,6 +71,25 @@ bool PhysicsShape::init(PhysicsBody* body, Type type) return true; } +void PhysicsShape::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (_body->getWorld() && _body->isEnable()) + { + if (enable) + { + _body->getWorld()->addShape(this); + }else + { + _body->getWorld()->removeShape(this); + } + } + } +} + void PhysicsShape::addToBody() { if(_body != nullptr) _body->addShape(this); diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index 79cda68e6d..4cc1da148b 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -58,6 +58,10 @@ public: public: inline PhysicsBody* getBody(){ return _body; } inline Type getType() { return _type; } + inline void setTag(int tag) { _tag = tag; } + inline int getTag() { return _tag; } + void setEnable(bool enable); + inline bool isEnable() { return _enable; } protected: bool init(PhysicsBody* body, Type type); @@ -77,6 +81,8 @@ protected: PhysicsBody* _body; PhysicsShapeInfo* _info; Type _type; + int _tag; + bool _enable; friend class PhysicsWorld; friend class PhysicsBody; diff --git a/cocos2dx/physics/CCPhysicsWorld.cpp b/cocos2dx/physics/CCPhysicsWorld.cpp index 08857de24b..17b866c6b7 100644 --- a/cocos2dx/physics/CCPhysicsWorld.cpp +++ b/cocos2dx/physics/CCPhysicsWorld.cpp @@ -34,6 +34,7 @@ #include "CCPhysicsBody.h" #include "CCPhysicsShape.h" #include "CCPhysicsContact.h" +#include "CCPhysicsJoint.h" #include "chipmunk/CCPhysicsWorldInfo.h" #include "Box2D/CCPhysicsWorldInfo.h" @@ -43,6 +44,8 @@ #include "Box2D/CCPhysicsShapeInfo.h" #include "chipmunk/CCPhysicsContactInfo.h" #include "Box2D/CCPhysicsContactInfo.h" +#include "chipmunk/CCPhysicsJointInfo.h" +#include "Box2D/CCPhysicsJointInfo.h" #include "chipmunk/CCPhysicsHelper.h" #include "draw_nodes/CCDrawNode.h" @@ -110,34 +113,69 @@ bool PhysicsWorld::init() return true; } +void PhysicsWorld::addJoint(PhysicsJoint* joint) +{ + auto it = std::find(_joints.begin(), _joints.end(), joint); + + if (it == _joints.end()) + { + _joints.push_back(joint); + + if (!cpSpaceContainsConstraint(_info->space, joint->_info->joint)) + { + cpSpaceAddConstraint(_info->space, joint->_info->joint); + } + } + +} + +void PhysicsWorld::removeJoint(PhysicsJoint* joint) +{ + +} + +void PhysicsWorld::removeAllJoints() +{ + +} + void PhysicsWorld::addShape(PhysicsShape* shape) { - for (auto it = shape->_info->shapes.begin(); it != shape->_info->shapes.end(); it++) + for (auto cps : shape->_info->shapes) { + if (cpSpaceContainsShape(_info->space, cps)) + { + continue; + } + if (cpBodyIsStatic(shape->getBody()->_info->body)) { - cpSpaceAddStaticShape(_info->space, *it); + cpSpaceAddStaticShape(_info->space, cps); }else { - cpSpaceAddShape(_info->space, *it); + cpSpaceAddShape(_info->space, cps); } } } -void PhysicsWorld::addChild(PhysicsBody* body) +void PhysicsWorld::addBody(PhysicsBody* body) { - auto shapes = body->getShapes(); - - // add body to space - if (body->isDynamic()) + if (body->isEnable()) { - cpSpaceAddBody(_info->space, body->_info->body); - } - - // add shapes to space - for (auto it = shapes.begin(); it != shapes.end(); it++) - { - addShape(*it); + // add body to space + if (body->isDynamic()) + { + cpSpaceAddBody(_info->space, body->_info->body); + } + + // add shapes to space + for (auto shape : body->getShapes()) + { + if (shape->isEnable()) + { + addShape(shape); + } + } } if (_bodys == nullptr) @@ -150,6 +188,54 @@ void PhysicsWorld::addChild(PhysicsBody* body) } } +void PhysicsWorld::removeBody(PhysicsBody* body) +{ + for (auto shape : body->getShapes()) + { + for (auto cps : shape->_info->shapes) + { + if (cpSpaceContainsShape(_info->space, cps)) + { + cpSpaceRemoveShape(_info->space, cps); + } + } + } + + if (cpSpaceContainsBody(_info->space, body->_info->body)) + { + cpSpaceRemoveBody(_info->space, body->_info->body); + } + + if (_bodys != nullptr) + { + _bodys->removeObject(body); + } +} + +void PhysicsWorld::removeBodyByTag(int tag) +{ + for (Object* obj : *_bodys) + { + PhysicsBody* body = dynamic_cast(obj); + if (body->getTag() == tag) + { + removeBody(body); + return; + } + } +} + +void PhysicsWorld::removeShape(PhysicsShape* shape) +{ + for (auto cps : shape->_info->shapes) + { + if (cpSpaceContainsShape(_info->space, cps)) + { + cpSpaceRemoveShape(_info->space, cps); + } + } +} + void PhysicsWorld::update(float delta) { cpSpaceStep(_info->space, delta); @@ -171,17 +257,16 @@ void PhysicsWorld::debugDraw() if (_debugDraw && _bodys != nullptr) { _drawNode= DrawNode::create(); - - Object* child = nullptr; - CCARRAY_FOREACH(_bodys, child) + + for (Object* obj : *_bodys) { - PhysicsBody* body = dynamic_cast(child); + PhysicsBody* body = dynamic_cast(obj); std::vector shapes = body->getShapes(); - for (auto it = shapes.begin(); it != shapes.end(); ++it) + for (auto shape : shapes) { - drawWithShape(_drawNode, *it); + drawWithShape(_drawNode, shape); } } diff --git a/cocos2dx/physics/CCPhysicsWorld.h b/cocos2dx/physics/CCPhysicsWorld.h index bd06fdf661..d7a30f37cf 100644 --- a/cocos2dx/physics/CCPhysicsWorld.h +++ b/cocos2dx/physics/CCPhysicsWorld.h @@ -28,6 +28,8 @@ #ifndef __CCPHYSICS_WORLD_H__ #define __CCPHYSICS_WORLD_H__ +#include + #include "cocoa/CCObject.h" #include "cocoa/CCGeometry.h" @@ -86,14 +88,18 @@ public: /** set the debug draw */ inline void setDebugDraw(bool debugDraw) { _debugDraw = debugDraw; } + virtual void removeBody(PhysicsBody* body); + virtual void removeBodyByTag(int tag); + protected: static PhysicsWorld* create(); bool init(); void setScene(Scene* scene); - virtual void addChild(PhysicsBody* body); + virtual void addBody(PhysicsBody* body); virtual void addShape(PhysicsShape* shape); + virtual void removeShape(PhysicsShape* shape); virtual void update(float delta); virtual void debugDraw(); @@ -120,6 +126,7 @@ protected: Array* _bodys; + std::list _joints; Scene* _scene; bool _debugDraw; @@ -132,6 +139,7 @@ protected: friend class Sprite; friend class Scene; friend class PhysicsBody; + friend class PhysicsShape; }; NS_CC_END diff --git a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp index 0734bf6e49..0e660792ad 100644 --- a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp +++ b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp @@ -36,12 +36,12 @@ PhysicsShapeInfo::PhysicsShapeInfo(PhysicsShape* shape) PhysicsShapeInfo::~PhysicsShapeInfo() { - for (auto it = shapes.begin(); it != shapes.end(); it++) + for (auto shape : shapes) { - cpShapeFree(*it); + auto it = map.find(shape); + if (it != map.end()) map.erase(shape); - auto mit = map.find(*it); - if (mit != map.end()) map.erase(*it); + cpShapeFree(shape); } } From 3dbe74db1aafd84bf217a8c496e2782e70d1dac3 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Sun, 29 Sep 2013 15:09:53 +0800 Subject: [PATCH 006/116] issue #2771: refactor PhysicsTest --- .../Classes/PhysicsTest/PhysicsTest.cpp | 267 +++++++++++------- .../TestCpp/Classes/PhysicsTest/PhysicsTest.h | 38 ++- 2 files changed, 200 insertions(+), 105 deletions(-) diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index 94f63e7f59..00d81cbd0f 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -2,40 +2,172 @@ #include "../testResource.h" USING_NS_CC; -PhysicsTestLayer::PhysicsTestLayer() -: _spriteTexture(nullptr) -, _scene(nullptr) + + +static std::function createFunctions[] = { + + CL(PhysicsDemoClickAdd), +}; + +static int sceneIdx=-1; +#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) + +namespace { + static Layer* next() + { + sceneIdx++; + sceneIdx = sceneIdx % MAX_LAYER; + + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } + + static Layer* back() + { + sceneIdx--; + int total = MAX_LAYER; + if( sceneIdx < 0 ) + sceneIdx += total; + + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } + + static Layer* restart() + { + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } +} + +bool PhysicsTestScene::initTest() +{ +#ifdef CC_USE_PHYSICS + if (TestScene::initWithPhysics()) + { + this->getPhysicsWorld()->setDebugDraw(true); + return true; + } +#else + return TestScene::init(); +#endif + + return false; +} + +void PhysicsTestScene::runThisTest() +{ +#ifdef CC_USE_PHYSICS + sceneIdx = -1; + addChild(next()); + + Director::getInstance()->replaceScene(this); +#else +#endif +} + +PhysicsDemo::PhysicsDemo() +: _scene(nullptr) +{ + +} + +PhysicsDemo::~PhysicsDemo() +{ + +} + +std::string PhysicsDemo::title() +{ + return "PhysicsTest"; +} + +std::string PhysicsDemo::subtitle() +{ + return ""; +} + +void PhysicsDemo::restartCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->addChild( restart() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::nextCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->addChild( next() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::backCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->addChild( back() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::onEnter() +{ + BaseTest::onEnter(); + + _scene = dynamic_cast(this->getParent()); +#ifdef CC_USE_PHYSICS + // menu for debug layer + MenuItemFont::setFontSize(18); + auto item = MenuItemFont::create("Toggle debug", CC_CALLBACK_1(PhysicsDemo::toggleDebugCallback, this)); + + auto menu = Menu::create(item, NULL); + this->addChild(menu); + menu->setPosition(Point(VisibleRect::right().x-50, VisibleRect::top().y-10)); +#else +#endif +} + + +void PhysicsDemo::toggleDebugCallback(Object* sender) +{ +#ifdef CC_USE_PHYSICS + if (_scene != nullptr) + { + _scene->getPhysicsWorld()->setDebugDraw(!_scene->getPhysicsWorld()->isDebugDraw()); + } +#endif +} + +void PhysicsDemoClickAdd::onEnter() +{ + PhysicsDemo::onEnter(); + #ifdef CC_USE_PHYSICS setTouchEnabled(true); setAccelerometerEnabled(true); - // title - auto label = LabelTTF::create("Multi touch the screen", "Marker Felt", 36); - label->setPosition(Point( VisibleRect::center().x, VisibleRect::top().y - 30)); - this->addChild(label, -1); - - // menu for debug layer - MenuItemFont::setFontSize(18); - auto item = MenuItemFont::create("Toggle debug", CC_CALLBACK_1(PhysicsTestLayer::toggleDebugCallback, this)); - - auto menu = Menu::create(item, NULL); - this->addChild(menu); - menu->setPosition(Point(VisibleRect::right().x-100, VisibleRect::top().y-60)); - auto sp = Sprite::create(); auto body = PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size); sp->setPhysicsBody(body); - this->addChild(sp); sp->setPosition(VisibleRect::center()); + this->addChild(sp); auto parent = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100); _spriteTexture = parent->getTexture(); addNewSpriteAtPosition(VisibleRect::center()); - createResetButton(); - #else auto label = LabelTTF::create("Should define CC_USE_BOX2D or CC_USE_CHIPMUNK\n to run this test case", "Arial", @@ -47,41 +179,33 @@ PhysicsTestLayer::PhysicsTestLayer() #endif } -void PhysicsTestLayer::toggleDebugCallback(Object* sender) +void PhysicsDemoClickAdd::addNewSpriteAtPosition(Point p) { #ifdef CC_USE_PHYSICS - if (_scene != nullptr) - { - _scene->getPhysicsWorld()->setDebugDraw(!_scene->getPhysicsWorld()->isDebugDraw()); - } + CCLOG("Add sprite %0.2f x %02.f",p.x,p.y); + + int posx, posy; + + posx = CCRANDOM_0_1() * 200.0f; + posy = CCRANDOM_0_1() * 200.0f; + + posx = (posx % 4) * 85; + posy = (posy % 3) * 121; + + auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121)); + auto body = PhysicsBody::createBox(Size(48, 108)); + sp->setPhysicsBody(body); + this->addChild(sp); + sp->setPosition(p); #endif } -PhysicsTestLayer::~PhysicsTestLayer() +std::string PhysicsDemoClickAdd::subtitle() { + return "multi touch to add grossini"; } -void PhysicsTestLayer::createResetButton() -{ - auto reset = MenuItemImage::create("Images/r1.png", "Images/r2.png", [](Object *sender) { - auto s = new PhysicsTestScene(); - s->initTest(); - auto child = new PhysicsTestLayer(); - child->setScene(s); - s->addChild(child); - child->release(); - Director::getInstance()->replaceScene(s); - s->release(); - }); - - auto menu = Menu::create(reset, NULL); - - menu->setPosition(Point(VisibleRect::bottom().x, VisibleRect::bottom().y + 30)); - this->addChild(menu, -1); - -} - -void PhysicsTestLayer::onTouchesEnded(const std::vector& touches, Event* event) +void PhysicsDemoClickAdd::onTouchesEnded(const std::vector& touches, Event* event) { //Add a new body/atlas sprite at the touched location @@ -93,8 +217,7 @@ void PhysicsTestLayer::onTouchesEnded(const std::vector& touches, Event* } } - -void PhysicsTestLayer::onAcceleration(Acceleration* acc, Event* event) +void PhysicsDemoClickAdd::onAcceleration(Acceleration* acc, Event* event) { #ifdef CC_USE_PHYSICS static float prevX=0, prevY=0; @@ -115,50 +238,4 @@ void PhysicsTestLayer::onAcceleration(Acceleration* acc, Event* event) _scene->getPhysicsWorld()->setGravity(v); } #endif -} - -void PhysicsTestLayer::addNewSpriteAtPosition(Point p) -{ -#ifdef CC_USE_PHYSICS - CCLOG("Add sprite %0.2f x %02.f",p.x,p.y); - - int posx, posy; - - posx = CCRANDOM_0_1() * 200.0f; - posy = CCRANDOM_0_1() * 200.0f; - - posx = (posx % 4) * 85; - posy = (posy % 3) * 121; - - auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121)); - auto body = PhysicsBody::createBox(Size(48, 108)); - sp->setPhysicsBody(body); - sp->setPosition(p); - this->addChild(sp); -#endif -} - -bool PhysicsTestScene::initTest() -{ -#ifdef CC_USE_PHYSICS - if (TestScene::initWithPhysics()) - { - this->getPhysicsWorld()->setDebugDraw(true); - return true; - } -#else - return TestScene::init(); -#endif - - return false; -} - -void PhysicsTestScene::runThisTest() -{ - auto layer = new PhysicsTestLayer(); - layer->setScene(this); - addChild(layer); - layer->release(); - - Director::getInstance()->replaceScene(this); -} +} \ No newline at end of file diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h index 3c95ed90c8..5acb33e855 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h @@ -3,24 +3,42 @@ #include "cocos2d.h" #include "../testBasic.h" +#include "../BaseTest.h" -class PhysicsTestLayer : public Layer + +class PhysicsDemo : public BaseTest { - Texture2D* _spriteTexture; // weak ref +protected: Scene* _scene; public: - PhysicsTestLayer(); - ~PhysicsTestLayer(); - - void createResetButton(); + PhysicsDemo(); + virtual ~PhysicsDemo(); - inline void setScene(Scene* scene) { _scene = scene; } + virtual void onEnter(); + virtual std::string title(); + virtual std::string subtitle(); + + void restartCallback(Object* sender); + void nextCallback(Object* sender); + void backCallback(Object* sender); void toggleDebugCallback(Object* sender); +}; + +class PhysicsDemoClickAdd : public PhysicsDemo +{ +private: + Texture2D* _spriteTexture; // weak ref + +public: + void onEnter(); + std::string subtitle(); + void addNewSpriteAtPosition(Point p); - virtual void onTouchesEnded(const std::vector& touches, Event* event) override; - virtual void onAcceleration(Acceleration* acc, Event* event) override; -} ; + + void onTouchesEnded(const std::vector& touches, Event* event); + void onAcceleration(Acceleration* acc, Event* event); +}; class PhysicsTestScene : public TestScene { From 18a4b18368cd2977f875ead4e4548ebf960b9e5a Mon Sep 17 00:00:00 2001 From: boyu0 Date: Mon, 30 Sep 2013 13:02:17 +0800 Subject: [PATCH 007/116] issue #2771: move _physicsBody from sprite to node --- cocos2dx/base_nodes/CCNode.cpp | 62 +++++++++++++++++++ cocos2dx/base_nodes/CCNode.h | 23 +++++++ .../CCScene.cpp | 10 +-- cocos2dx/physics/CCPhysicsBody.cpp | 13 ++-- cocos2dx/physics/CCPhysicsBody.h | 2 +- cocos2dx/physics/CCPhysicsWorld.cpp | 4 ++ cocos2dx/sprite_nodes/CCSprite.cpp | 47 -------------- cocos2dx/sprite_nodes/CCSprite.h | 18 ------ .../Classes/PhysicsTest/PhysicsTest.cpp | 26 ++++---- 9 files changed, 115 insertions(+), 90 deletions(-) diff --git a/cocos2dx/base_nodes/CCNode.cpp b/cocos2dx/base_nodes/CCNode.cpp index f4547bb1fa..95f1a94987 100644 --- a/cocos2dx/base_nodes/CCNode.cpp +++ b/cocos2dx/base_nodes/CCNode.cpp @@ -44,6 +44,10 @@ THE SOFTWARE. #include "event_dispatcher/CCEvent.h" #include "event_dispatcher/CCEventTouch.h" +#ifdef CC_USE_PHYSICS +#include "physics/CCPhysicsBody.h" +#endif + // externals #include "kazmath/GL/matrix.h" #include "support/component/CCComponent.h" @@ -128,6 +132,11 @@ Node::Node(void) , _componentContainer(NULL) , _eventPriority(0) , _oldEventPriority(0) +#ifdef CC_USE_PHYSICS +, _physicsBody(nullptr) +, _physicsPositionMark(true) +, _physicsRotationMark(true) +#endif { // set default scheduler and actionManager Director *director = Director::getInstance(); @@ -179,6 +188,10 @@ Node::~Node() CC_SAFE_DELETE(_componentContainer); removeAllEventListeners(); + +#ifdef CC_USE_PHYSICS + CC_SAFE_RELEASE(_physicsBody); +#endif } bool Node::init() @@ -257,6 +270,15 @@ void Node::setRotation(float newRotation) { _rotationX = _rotationY = newRotation; _transformDirty = _inverseDirty = true; + +#ifdef CC_USE_PHYSICS + if (_physicsBody && _physicsRotationMark) + { + _physicsBody->setRotation(newRotation); + } + + _physicsRotationMark = true; +#endif } float Node::getRotationX() const @@ -332,6 +354,15 @@ void Node::setPosition(const Point& newPosition) { _position = newPosition; _transformDirty = _inverseDirty = true; + +#ifdef CC_USE_PHYSICS + if (_physicsBody && _physicsPositionMark) + { + _physicsBody->setPosition(newPosition); + } + + _physicsPositionMark = true; +#endif } void Node::getPosition(float* x, float* y) const @@ -800,6 +831,17 @@ void Node::visit() { return; } + +#ifdef CC_USE_PHYSICS + if (_physicsBody) + { + _physicsPositionMark = false; + _physicsRotationMark = false; + setPosition(_physicsBody->getPosition()); + setRotation(_physicsBody->getRotation()); + } +#endif + kmGLPushMatrix(); if (_grid && _grid->isActive()) @@ -1329,6 +1371,26 @@ void Node::setDirtyForAllEventListeners() } } +#ifdef CC_USE_PHYSICS +void Node::setPhysicsBody(PhysicsBody* body) +{ + if (_physicsBody != nullptr) + { + _physicsBody->release(); + } + + _physicsBody = body; + _physicsBody->retain(); + _physicsBody->setPosition(getPosition()); + _physicsBody->setRotation(getRotation()); +} + +PhysicsBody* Node::getPhysicsBody() const +{ + return _physicsBody; +} +#endif //CC_USE_PHYSICS + // NodeRGBA NodeRGBA::NodeRGBA() : _displayedOpacity(255) diff --git a/cocos2dx/base_nodes/CCNode.h b/cocos2dx/base_nodes/CCNode.h index e335ff11fd..41d16dbcf3 100644 --- a/cocos2dx/base_nodes/CCNode.h +++ b/cocos2dx/base_nodes/CCNode.h @@ -38,6 +38,7 @@ #include "script_support/CCScriptSupport.h" #include "CCProtocols.h" #include "event_dispatcher/CCEventDispatcher.h" +#include "physics/CCPhysicsSetting.h" #include @@ -56,6 +57,9 @@ class Component; class Dictionary; class ComponentContainer; class EventDispatcher; +#ifdef CC_USE_PHYSICS +class PhysicsBody; +#endif /** * @addtogroup base_nodes @@ -1365,6 +1369,19 @@ public: */ virtual void removeAllComponents(); /// @} end of component functions + + +#ifdef CC_USE_PHYSICS + /** + * set the PhysicsBody that let the sprite effect with physics + */ + virtual void setPhysicsBody(PhysicsBody* body); + + /** + * get the PhysicsBody the sprite have + */ + PhysicsBody* getPhysicsBody() const; +#endif private: @@ -1477,6 +1494,12 @@ protected: int _eventPriority; ///< The scene graph based priority of event listener. int _oldEventPriority; ///< The old scene graph based priority of event listener. static int _globalEventPriorityIndex; ///< The index of global event priority. + +#ifdef CC_USE_PHYSICS + PhysicsBody* _physicsBody; ///< the physicsBody the node have + bool _physicsPositionMark; ///< set this mark to false will skip the setRotation to physicsBody one time + bool _physicsRotationMark; ///< set this mark to false will skip the setPosition to physicsBody one time +#endif }; //#pragma mark - NodeRGBA diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp index 0950fcd0a8..50b67e50e0 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp +++ b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp @@ -129,15 +129,15 @@ void Scene::addChildToPhysicsWorld(Node* child) { if (_physicsWorld) { - auto addToPhysicsWorldFunc = [this](Object* node) -> void + auto addToPhysicsWorldFunc = [this](Object* child) -> void { - if (dynamic_cast(node) != nullptr) + if (dynamic_cast(child) != nullptr) { - Sprite* sp = dynamic_cast(node); + Node* node = dynamic_cast(child); - if (sp->getPhysicsBody()) + if (node->getPhysicsBody()) { - _physicsWorld->addBody(sp->getPhysicsBody()); + _physicsWorld->addBody(node->getPhysicsBody()); } } }; diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index 2c190eefdd..32f41fd649 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -273,16 +273,19 @@ bool PhysicsBody::init() void PhysicsBody::setDynamic(bool dynamic) { - _dynamic = dynamic; - if (_world != nullptr && cpBodyIsStatic(_info->body) == (cpBool)_dynamic) + if (dynamic != _dynamic) { if (dynamic) { - cpSpaceConvertBodyToDynamic(_world->_info->space, _info->body, _mass, _angularDamping); + cpBodySetMass(_info->body, PhysicsHelper::float2cpfloat(_mass)); + cpBodySetMoment(_info->body, PhysicsHelper::float2cpfloat(_angularDamping)); }else { - cpSpaceConvertBodyToStatic(_world->_info->space, _info->body); + cpBodySetMass(_info->body, INFINITY); + cpBodySetMoment(_info->body, INFINITY); } + + _dynamic = dynamic; } } @@ -293,7 +296,7 @@ bool PhysicsBody::initStatic() _info = new PhysicsBodyInfo(); CC_BREAK_IF(_info == nullptr); - _info->body = cpBodyNewStatic(); + _info->body = cpBodyNew(INFINITY, INFINITY); CC_BREAK_IF(_info->body == nullptr); _dynamic = false; diff --git a/cocos2dx/physics/CCPhysicsBody.h b/cocos2dx/physics/CCPhysicsBody.h index 94d30f8b63..9bca83b3c0 100644 --- a/cocos2dx/physics/CCPhysicsBody.h +++ b/cocos2dx/physics/CCPhysicsBody.h @@ -259,7 +259,7 @@ protected: friend class PhysicsWorld; friend class PhysicsShape; friend class PhysicsJoint; - friend class Sprite; + friend class Node; }; NS_CC_END diff --git a/cocos2dx/physics/CCPhysicsWorld.cpp b/cocos2dx/physics/CCPhysicsWorld.cpp index b67ac5a65a..580fd5fe75 100644 --- a/cocos2dx/physics/CCPhysicsWorld.cpp +++ b/cocos2dx/physics/CCPhysicsWorld.cpp @@ -186,6 +186,8 @@ void PhysicsWorld::addBody(PhysicsBody* body) { _bodys->addObject(body); } + + body->retain(); } void PhysicsWorld::removeBody(PhysicsBody* body) @@ -210,6 +212,8 @@ void PhysicsWorld::removeBody(PhysicsBody* body) { _bodys->removeObject(body); } + + body->release(); } void PhysicsWorld::removeBodyByTag(int tag) diff --git a/cocos2dx/sprite_nodes/CCSprite.cpp b/cocos2dx/sprite_nodes/CCSprite.cpp index 741a1e1683..e1cfd9b5da 100644 --- a/cocos2dx/sprite_nodes/CCSprite.cpp +++ b/cocos2dx/sprite_nodes/CCSprite.cpp @@ -296,18 +296,12 @@ Sprite* Sprite::initWithCGImage(CGImageRef pImage, const char *pszKey) Sprite::Sprite(void) : _shouldBeHidden(false) , _texture(nullptr) -#ifdef CC_USE_PHYSICS -, _physicsBody(nullptr) -#endif { } Sprite::~Sprite(void) { CC_SAFE_RELEASE(_texture); -#ifdef CC_USE_PHYSICS - CC_SAFE_RELEASE(_physicsBody); -#endif } void Sprite::setTextureRect(const Rect& rect) @@ -790,13 +784,6 @@ void Sprite::setPosition(const Point& pos) { Node::setPosition(pos); SET_DIRTY_RECURSIVELY(); - -#ifdef CC_USE_PHYSICS - if (_physicsBody) - { - _physicsBody->setPosition(pos); - } -#endif } void Sprite::setRotation(float rotation) @@ -804,13 +791,6 @@ void Sprite::setRotation(float rotation) Node::setRotation(rotation); SET_DIRTY_RECURSIVELY(); - -#ifdef CC_USE_PHYSICS - if (_physicsBody) - { - _physicsBody->setRotation(rotation); - } -#endif } void Sprite::setRotationX(float fRotationX) @@ -907,33 +887,6 @@ bool Sprite::isFlippedY(void) const return _flippedY; } -#ifdef CC_USE_PHYSICS -void Sprite::setPhysicsBody(PhysicsBody* body) -{ - _physicsBody = body; - _physicsBody->retain(); - _physicsBody->setPosition(getPosition()); - _physicsBody->setRotation(getRotation()); -} - -PhysicsBody* Sprite::getPhysicsBody() const -{ - return _physicsBody; -} - -void Sprite::visit() -{ - if (_physicsBody) - { - Node::setPosition(_physicsBody->getPosition()); - Node::setRotation(_physicsBody->getRotation()); - SET_DIRTY_RECURSIVELY(); - } - - Node::visit(); -} -#endif //CC_USE_PHYSICS - // // RGBA protocol // diff --git a/cocos2dx/sprite_nodes/CCSprite.h b/cocos2dx/sprite_nodes/CCSprite.h index 815cd67614..d150c55213 100644 --- a/cocos2dx/sprite_nodes/CCSprite.h +++ b/cocos2dx/sprite_nodes/CCSprite.h @@ -461,20 +461,6 @@ public: */ void setFlippedY(bool flippedY); -#ifdef CC_USE_PHYSICS - /** - * set the PhysicsBody that let the sprite effect with physics - */ - virtual void setPhysicsBody(PhysicsBody* body); - - /** - * get the PhysicsBody the sprite have - */ - PhysicsBody* getPhysicsBody() const; - - virtual void visit() override; -#endif - /// @} End of Sprite properties getter/setters /** @deprecated Use isFlippedY() instead */ @@ -590,10 +576,6 @@ protected: // image is flipped bool _flippedX; /// Whether the sprite is flipped horizaontally or not. bool _flippedY; /// Whether the sprite is flipped vertically or not. - -#ifdef CC_USE_PHYSICS - PhysicsBody* _physicsBody; ///< the physicsBody the node have -#endif }; diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index 00d81cbd0f..db4c3d46ab 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -2,18 +2,16 @@ #include "../testResource.h" USING_NS_CC; - - -static std::function createFunctions[] = { - - CL(PhysicsDemoClickAdd), -}; - -static int sceneIdx=-1; -#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) - namespace { + static std::function createFunctions[] = { + + CL(PhysicsDemoClickAdd), + }; + + static int sceneIdx=-1; +#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) + static Layer* next() { sceneIdx++; @@ -157,11 +155,11 @@ void PhysicsDemoClickAdd::onEnter() setTouchEnabled(true); setAccelerometerEnabled(true); - auto sp = Sprite::create(); + auto node = Node::create(); auto body = PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size); - sp->setPhysicsBody(body); - sp->setPosition(VisibleRect::center()); - this->addChild(sp); + node->setPhysicsBody(body); + node->setPosition(VisibleRect::center()); + this->addChild(node); auto parent = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100); _spriteTexture = parent->getTexture(); From 6aa18423e6ed8ab5edb6df0d8a4808f64189dcf7 Mon Sep 17 00:00:00 2001 From: samuelhu Date: Mon, 30 Sep 2013 16:22:55 +0800 Subject: [PATCH 008/116] issue #2792 : Performance Test: Sprite drawing --- cocos2dx/CCDirector.h | 5 + .../PerformanceTest/PerformanceSpriteTest.cpp | 290 +++++++++++++++++- .../PerformanceTest/PerformanceSpriteTest.h | 26 +- 3 files changed, 312 insertions(+), 9 deletions(-) diff --git a/cocos2dx/CCDirector.h b/cocos2dx/CCDirector.h index 8b61b12a96..9cc20393ea 100644 --- a/cocos2dx/CCDirector.h +++ b/cocos2dx/CCDirector.h @@ -353,6 +353,11 @@ public: void setActionManager(ActionManager* actionManager); /* Gets delta time since last tick to main loop */ float getDeltaTime() const; + + /** + * get Frame Rate + */ + float getFrameRate() const { return _frameRate; } protected: void purgeDirector(); diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.cpp b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.cpp index 76c423fb82..b00cef317c 100644 --- a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.cpp @@ -10,11 +10,10 @@ enum { enum { kTagInfoLayer = 1, kTagMainLayer = 2, + kTagAutoTestMenu = 3, kTagMenuLayer = (kMaxNodes + 1000), }; -static int s_nSpriteCurCase = 0; - //////////////////////////////////////////////////////// // // SubTest @@ -227,6 +226,37 @@ void SubTest::removeByTag(int tag) // SpriteMenuLayer // //////////////////////////////////////////////////////// +void SpriteMenuLayer::restartCallback(Object* sender) +{ + if ( SpriteMainScene::_s_autoTest ) + { + log("It's auto sprite performace testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::restartCallback(sender); +} +void SpriteMenuLayer::nextCallback(Object* sender) +{ + if ( SpriteMainScene::_s_autoTest ) + { + log("It's auto sprite performace testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::nextCallback(sender); +} +void SpriteMenuLayer::backCallback(Object* sender) +{ + if ( SpriteMainScene::_s_autoTest ) + { + log("It's auto sprite performace testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::backCallback(sender); +} + void SpriteMenuLayer::showCurrentTest() { SpriteMainScene* scene = NULL; @@ -258,7 +288,8 @@ void SpriteMenuLayer::showCurrentTest() scene = new SpritePerformTest7; break; } - s_nSpriteCurCase = _curCase; + + SpriteMainScene::_s_nSpriteCurCase = _curCase; if (scene) { @@ -267,12 +298,15 @@ void SpriteMenuLayer::showCurrentTest() scene->release(); } } - //////////////////////////////////////////////////////// // // SpriteMainScene // //////////////////////////////////////////////////////// + +bool SpriteMainScene::_s_autoTest = false; +int SpriteMainScene::_s_nSpriteCurCase = 0; + void SpriteMainScene::initWithSubTest(int asubtest, int nNodes) { //srandom(0); @@ -303,10 +337,33 @@ void SpriteMainScene::initWithSubTest(int asubtest, int nNodes) addChild(infoLabel, 1, kTagInfoLayer); // add menu - auto menuLayer = new SpriteMenuLayer(true, TEST_COUNT, s_nSpriteCurCase); + auto menuLayer = new SpriteMenuLayer(true, TEST_COUNT, SpriteMainScene::_s_nSpriteCurCase); addChild(menuLayer, 1, kTagMenuLayer); menuLayer->release(); - + + /** + * auto test menu + */ + + auto menuAutoTest = Menu::create(); + menuAutoTest->setPosition( Point::ZERO ); + MenuItemFont::setFontName("Arial"); + MenuItemFont::setFontSize(24); + + MenuItemFont* autoTestItem = NULL; + if (SpriteMainScene::_s_autoTest) + { + autoTestItem = MenuItemFont::create("Auto Test On",CC_CALLBACK_1(SpriteMainScene::onAutoTest, this)); + } + else + { + autoTestItem = MenuItemFont::create("Auto Test Off",CC_CALLBACK_1(SpriteMainScene::onAutoTest, this)); + } + autoTestItem->setTag(1); + autoTestItem->setPosition(Point( s.width - 90, s.height / 2)); + menuAutoTest->addChild(autoTestItem); + addChild( menuAutoTest, 3, kTagAutoTestMenu ); + // Sub Tests MenuItemFont::setFontSize(32); auto subMenu = Menu::create(); @@ -356,6 +413,12 @@ SpriteMainScene::~SpriteMainScene() void SpriteMainScene::testNCallback(Object* sender) { + if (SpriteMainScene::_s_autoTest) + { + log("It's auto sprite performace testing,so this operation is invalid"); + return; + } + subtestNumber = static_cast(sender)->getTag(); auto menu = static_cast( getChildByTag(kTagMenuLayer) ); menu->restartCallback(sender); @@ -375,7 +438,7 @@ void SpriteMainScene::updateNodes() } void SpriteMainScene::onIncrease(Object* sender) -{ +{ if( quantityNodes >= kMaxNodes) return; @@ -391,6 +454,7 @@ void SpriteMainScene::onIncrease(Object* sender) void SpriteMainScene::onDecrease(Object* sender) { + if( quantityNodes <= 0 ) return; @@ -403,6 +467,216 @@ void SpriteMainScene::onDecrease(Object* sender) updateNodes(); } +void SpriteMainScene::dumpProfilerFPS() +{ + if (_vecFPS.empty()) + { + log("Error: the FPS vector is empty"); + return; + } + + auto iter = _vecFPS.begin(); + float minFPS = *iter; + float maxFPS = *iter; + float totalFPS = 0.0f; + float averagerFPS = 0.0f; + for (; iter != _vecFPS.end(); ++iter) + { + if (minFPS > *iter) + { + minFPS = *iter; + } + + if (maxFPS < *iter) + { + maxFPS = *iter; + } + + totalFPS += *iter; + } + + averagerFPS = totalFPS / _vecFPS.size(); + log("Cur test: %d, cur sub item :%d,cur sprite nums:%d, the min FPS value is %.1f,the max FPS value is %.1f,the averager FPS is %.1f", SpriteMainScene::_s_nSpriteCurCase, subtestNumber, quantityNodes, minFPS, maxFPS, averagerFPS); + +} + +void SpriteMainScene::updateAutoTest(float dt) +{ + if (SpriteMainScene::_s_autoTest) + { + _executeTimes += 1; + _vecFPS.push_back(Director::getInstance()->getFrameRate()); + if ( _executeTimes >= SpriteMainScene::MAX_AUTO_TEST_TIMES ) + { + dumpProfilerFPS(); + nextAutoTest(); + } + } +} + +void SpriteMainScene::onEnter() +{ + Scene::onEnter(); + + if ( SpriteMainScene::_s_autoTest ) + { + _vecFPS.clear(); + _executeTimes = 0; + + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + + sched->scheduleSelector(SEL_SCHEDULE(&SpriteMainScene::updateAutoTest), this, 0.2, false); + + } +} + +void SpriteMainScene::onExit() +{ + if ( SpriteMainScene::_s_autoTest ) + { + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + + sched->unscheduleSelector(SEL_SCHEDULE(&SpriteMainScene::updateAutoTest), this ); + } + + Scene::onExit(); +} + +void SpriteMainScene::autoShowSpriteTests(int curCase, int subTest,int nodes) +{ + + SpriteMainScene* scene = NULL; + + switch (curCase) + { + case 0: + scene = new SpritePerformTest1; + break; + case 1: + scene = new SpritePerformTest2; + break; + case 2: + scene = new SpritePerformTest3; + break; + case 3: + scene = new SpritePerformTest4; + break; + case 4: + scene = new SpritePerformTest5; + break; + case 5: + scene = new SpritePerformTest6; + break; + case 6: + scene = new SpritePerformTest7; + break; + } + + SpriteMainScene::_s_nSpriteCurCase = curCase; + + if (scene) + { + scene->initWithSubTest(subTest, nodes); + Director::getInstance()->replaceScene(scene); + scene->release(); + } +} + +void SpriteMainScene::beginAutoTest() +{ + if (0 != SpriteMainScene::_s_nSpriteCurCase) + { + SpriteMainScene::_s_nSpriteCurCase = 0; + } + + auto scene = new SpritePerformTest1; + scene->initWithSubTest(1, 500); + Director::getInstance()->replaceScene(scene); + scene->release(); +} + +void SpriteMainScene::endAutoTest() +{ + SpriteMainScene::_s_autoTest = false; + + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + + sched->unscheduleSelector( SEL_SCHEDULE( &SpriteMainScene::updateAutoTest ), this ); +} + +void SpriteMainScene::nextAutoTest() +{ + if ( SpriteMainScene::_s_nSpriteCurCase < SpriteMainScene::MAX_SPRITE_TEST_CASE ) + { + if ( subtestNumber < SpriteMainScene::MAX_SUB_TEST_NUMS ) + { + subtestNumber += 1; + autoShowSpriteTests(SpriteMainScene::_s_nSpriteCurCase, subtestNumber, quantityNodes); + } + else if ( subtestNumber == SpriteMainScene::MAX_SUB_TEST_NUMS ) + { + if (quantityNodes == SpriteMainScene::AUTO_TEST_NODE_NUM1) + { + autoShowSpriteTests(SpriteMainScene::_s_nSpriteCurCase, 1, SpriteMainScene::AUTO_TEST_NODE_NUM2); + } + else + { + if (SpriteMainScene::_s_nSpriteCurCase + 1 < SpriteMainScene::MAX_SPRITE_TEST_CASE) + { + SpriteMainScene::_s_nSpriteCurCase += 1; + autoShowSpriteTests(SpriteMainScene::_s_nSpriteCurCase, 1, SpriteMainScene::AUTO_TEST_NODE_NUM1); + } + else + { + finishAutoTest(); + } + } + } + } +} + +void SpriteMainScene::finishAutoTest() +{ + SpriteMainScene::_s_autoTest = false; + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + sched->unscheduleSelector( SEL_SCHEDULE( &SpriteMainScene::updateAutoTest ), this); + + auto autoTestMenu = dynamic_cast(getChildByTag(kTagAutoTestMenu)); + if (nullptr != autoTestMenu) + { + auto menuItemFont = dynamic_cast(autoTestMenu->getChildByTag(1)); + if (nullptr != menuItemFont) + { + menuItemFont->setString("Auto Test finish"); + } + } + + log("Sprite performance test is finish "); +} + +void SpriteMainScene::onAutoTest(Object* sender) +{ + SpriteMainScene::_s_autoTest = !SpriteMainScene::_s_autoTest; + MenuItemFont* menuItem = dynamic_cast(sender); + if (nullptr != menuItem) + { + if (SpriteMainScene::_s_autoTest) + { + menuItem->setString("Auto Test On"); + beginAutoTest(); + } + else + { + menuItem->setString("Auto Test Off"); + endAutoTest(); + } + } +} + //////////////////////////////////////////////////////// // // For test functions @@ -498,7 +772,6 @@ void SpritePerformTest1::doTest(Sprite* sprite) { performancePosition(sprite); } - //////////////////////////////////////////////////////// // // SpritePerformTest2 @@ -609,6 +882,7 @@ void SpritePerformTest7::doTest(Sprite* sprite) void runSpriteTest() { + SpriteMainScene::_s_autoTest = false; auto scene = new SpritePerformTest1; scene->initWithSubTest(1, 50); Director::getInstance()->replaceScene(scene); diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.h b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.h index da7f009ec3..b9d72a399e 100644 --- a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.h +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceSpriteTest.h @@ -25,6 +25,9 @@ public: { } + virtual void restartCallback(Object* sender); + virtual void nextCallback(Object* sender); + virtual void backCallback(Object* sender); virtual void showCurrentTest(); }; @@ -45,12 +48,33 @@ public: int getSubTestNum() { return subtestNumber; } int getNodesNum() { return quantityNodes; } - + + virtual void onEnter(); + virtual void onExit(); + void updateAutoTest(float dt); + void onAutoTest(Object* sender); +private: + void dumpProfilerFPS(); + void beginAutoTest(); + void endAutoTest(); + void nextAutoTest(); + void finishAutoTest(); + void autoShowSpriteTests(int curCase, int subTest,int nodes); +public: + static bool _s_autoTest; + static int _s_nSpriteCurCase; protected: int lastRenderedCount; int quantityNodes; SubTest *_subTest; int subtestNumber; + std::vector _vecFPS; + int _executeTimes; + const int MAX_AUTO_TEST_TIMES = 25; + const int MAX_SPRITE_TEST_CASE = 7; + const int MAX_SUB_TEST_NUMS = 9; + const int AUTO_TEST_NODE_NUM1 = 500; + const int AUTO_TEST_NODE_NUM2 = 1500; }; class SpritePerformTest1 : public SpriteMainScene From 9c16a45f33aa0072c3587c03082978986cf28e1c Mon Sep 17 00:00:00 2001 From: boyu0 Date: Mon, 30 Sep 2013 20:43:19 +0800 Subject: [PATCH 009/116] issue #2771: separate the PhysicsBody and the PhysicsShape. --- cocos2dx/physics/CCPhysicsBody.cpp | 213 ++++++++++-------- cocos2dx/physics/CCPhysicsBody.h | 50 +--- cocos2dx/physics/CCPhysicsShape.cpp | 83 +++++-- cocos2dx/physics/CCPhysicsShape.h | 36 ++- .../Classes/PhysicsTest/PhysicsTest.cpp | 109 ++++++++- .../TestCpp/Classes/PhysicsTest/PhysicsTest.h | 38 ++-- 6 files changed, 345 insertions(+), 184 deletions(-) diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index 32f41fd649..b8a961a302 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -62,7 +62,7 @@ PhysicsBody::PhysicsBody() : _owner(nullptr) , _world(nullptr) , _info(nullptr) -, _dynamic(false) +, _dynamic(true) , _enable(true) , _massDefault(true) , _angularDampingDefault(true) @@ -90,12 +90,12 @@ PhysicsBody::~PhysicsBody() } } -PhysicsBody* PhysicsBody::createCircle(float radius) +PhysicsBody* PhysicsBody::createCircle(float radius, float density) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addCircle(radius); + body->addShape(PhysicsShapeCircle::create(body, radius, density)); body->autorelease(); return body; } @@ -104,12 +104,12 @@ PhysicsBody* PhysicsBody::createCircle(float radius) return nullptr; } -PhysicsBody* PhysicsBody::createBox(Size size) +PhysicsBody* PhysicsBody::createBox(Size size, float density) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addBox(size); + body->addShape(PhysicsShapeBox::create(body, size, density)); body->autorelease(); return body; } @@ -118,12 +118,12 @@ PhysicsBody* PhysicsBody::createBox(Size size) return nullptr; } -PhysicsBody* PhysicsBody::createPolygon(Point* points, int count) +PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, float density) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addPolygon(points, count); + body->addShape(PhysicsShapePolygon::create(body, points, count, density)); body->autorelease(); return body; } @@ -135,9 +135,10 @@ PhysicsBody* PhysicsBody::createPolygon(Point* points, int count) PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeSegment(a, b, border); + body->addShape(PhysicsShapeEdgeSegment::create(body, a, b, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -149,9 +150,10 @@ PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1 PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeBox(size, border); + body->addShape(PhysicsShapeEdgeBox::create(body, size, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -164,9 +166,10 @@ PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgePolygon(points, count, border); + body->addShape(PhysicsShapePolygon::create(body, points, count, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -179,9 +182,10 @@ PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float bord PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeChain(points, count); + body->addShape(PhysicsShapeEdgeChain::create(body, points, count, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -191,69 +195,6 @@ PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border return nullptr; } -PhysicsShapeCircle* PhysicsBody::addCircle(float radius, Point offset/* = Point(0, 0)*/) -{ - _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); - setMass((_massDefault ? 0 : getMass()) + _area * _density); - - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForCircle(getMass(), 0, radius, PhysicsHelper::point2cpv(offset)))); - - return PhysicsShapeCircle::create(this, radius, offset); -} - -PhysicsShapeBox* PhysicsBody::addBox(Size size, Point offset/* = Point(0, 0)*/) -{ - cpVect cpOffset = PhysicsHelper::size2cpv(size); - cpVect vec[4] = {}; - vec[0] = cpv(0, 0); - vec[1] = cpv(0, cpOffset.y); - vec[2] = cpv(cpOffset.x, cpOffset.y); - vec[3] = cpv(cpOffset.x, 0); - - _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(4, vec)); - setMass((_massDefault ? 0 : getMass()) + _area * _density); - - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForBox(getMass(), PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)))); - - return PhysicsShapeBox::create(this, size, offset); -} - -PhysicsShapePolygon* PhysicsBody::addPolygon(Point* points, int count, Point offset/* = Point(0, 0)*/) -{ - cpVect* vec = new cpVect[count]; - PhysicsHelper::points2cpvs(points, vec, count); - _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vec)); - - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForPoly(getMass(), count, vec, PhysicsHelper::point2cpv(offset)))); - - delete[] vec; - - return PhysicsShapePolygon::create(this, points, count, offset); -} - -PhysicsShapeEdgeSegment* PhysicsBody::addEdgeSegment(Point a, Point b, float border/* = 1*/) -{ - return PhysicsShapeEdgeSegment::create(this, a, b, border); -} - -PhysicsShapeEdgeBox* PhysicsBody::addEdgeBox(Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) -{ - return PhysicsShapeEdgeBox::create(this, size, border, offset); -} - -PhysicsShapeEdgePolygon* PhysicsBody::addEdgePolygon(Point* points, int count, float border/* = 1*/) -{ - return PhysicsShapeEdgePolygon::create(this, points, count); -} - -PhysicsShapeEdgeChain* PhysicsBody::addEdgeChain(Point* points, int count, float border/* = 1*/) -{ - return PhysicsShapeEdgeChain::create(this, points, count, border); -} - bool PhysicsBody::init() { do @@ -263,7 +204,6 @@ bool PhysicsBody::init() _info->body = cpBodyNew(PhysicsHelper::float2cpfloat(_mass), PhysicsHelper::float2cpfloat(_angularDamping)); CC_BREAK_IF(_info->body == nullptr); - _dynamic = true; return true; } while (false); @@ -289,23 +229,6 @@ void PhysicsBody::setDynamic(bool dynamic) } } -bool PhysicsBody::initStatic() -{ - do - { - _info = new PhysicsBodyInfo(); - CC_BREAK_IF(_info == nullptr); - - _info->body = cpBodyNew(INFINITY, INFINITY); - CC_BREAK_IF(_info->body == nullptr); - _dynamic = false; - - return true; - } while (false); - - return false; -} - void PhysicsBody::setPosition(Point position) { cpBodySetPos(_info->body, PhysicsHelper::point2cpv(position)); @@ -331,9 +254,51 @@ void PhysicsBody::addShape(PhysicsShape* shape) { if (shape == nullptr) return; - _shapes.push_back(shape); + if (shape->getBody() != this) CCASSERT(false, ""); - if (_world != nullptr) _world->addShape(shape); + if (std::find(_shapes.begin(), _shapes.end(), shape) == _shapes.end()) + { + _shapes.push_back(shape); + shape->_isAddToBody = true; + + // calculate the mass, area and desity + _area += shape->getArea(); + if (_mass == INFINITY || shape->getMass() == INFINITY) + { + _mass = INFINITY; + _massDefault = false; + }else + { + if (shape->getMass() > 0) + { + _mass = (_massDefault ? 0 : _mass) + shape->getMass(); + _massDefault = false; + } + } + cpBodySetMass(_info->body, _mass); + + if (!_massDefault) + { + if (_mass == INFINITY) + { + _density = INFINITY; + }else + { + _density = _mass / _area; + } + } + + if (shape->getAngularDumping() > 0) + { + _angularDamping = (_angularDampingDefault ? 0 : _angularDamping) + shape->getAngularDumping(); + _angularDampingDefault = false; + cpBodySetMoment(_info->body, _angularDamping); + } + + if (_world != nullptr) _world->addShape(shape); + + shape->retain(); + } } void PhysicsBody::applyForce(Point force) @@ -369,6 +334,16 @@ void PhysicsBody::setMass(float mass) cpBodySetMass(_info->body, PhysicsHelper::float2cpfloat(_mass)); } +void PhysicsBody::setVelocity(Point velocity) +{ + cpBodySetVel(_info->body, PhysicsHelper::point2cpv(velocity)); +} + +Point PhysicsBody::getVelocity() +{ + return PhysicsHelper::cpv2point(cpBodyGetVel(_info->body)); +} + void PhysicsBody::setAngularDamping(float angularDamping) { _angularDamping = angularDamping; @@ -414,7 +389,47 @@ void PhysicsBody::removeShape(PhysicsShape* shape) } _shapes.erase(it); - delete shape; + shape->_isAddToBody = false; + + + // deduce the mass, area and angularDamping + if (_mass != INFINITY && shape->getMass() != INFINITY) + { + if (_mass - shape->getMass() <= 0) + { + _mass = MASS_DEFAULT; + _massDefault = true; + }else + { + _mass = _mass = shape->getMass(); + } + + _area -= shape->getArea(); + + if (_mass == INFINITY) + { + _density = INFINITY; + } + else if (_area > 0) + { + _density = _mass / _area; + } + else + { + _density = DENSITY_DEFAULT; + } + + if (_angularDamping - shape->getAngularDumping() > 0) + { + _angularDamping -= shape->getAngularDumping(); + }else + { + _angularDamping = ANGULARDAMPING_DEFAULT; + _angularDampingDefault = true; + } + } + + shape->release(); } } diff --git a/cocos2dx/physics/CCPhysicsBody.h b/cocos2dx/physics/CCPhysicsBody.h index 9bca83b3c0..580bec840d 100644 --- a/cocos2dx/physics/CCPhysicsBody.h +++ b/cocos2dx/physics/CCPhysicsBody.h @@ -37,13 +37,6 @@ class Sprite; class PhysicsWorld; class PhysicsJoint; class PhysicsShape; -class PhysicsShapeCircle; -class PhysicsShapeBox; -class PhysicsShapePolygon; -class PhysicsShapeEdgeSegment; -class PhysicsShapeEdgeBox; -class PhysicsShapeEdgePolygon; -class PhysicsShapeEdgeChain; class PhysicsBodyInfo; /** @@ -56,16 +49,16 @@ public: /** * @brief Create a body contains a circle shape. */ - static PhysicsBody* createCircle(float radius); + static PhysicsBody* createCircle(float radius, float density = 1); /** * @brief Create a body contains a box shape. */ - static PhysicsBody* createBox(Size size); + static PhysicsBody* createBox(Size size, float density = 1); /** * @brief Create a body contains a polygon shape. * points is an array of Point structs defining a convex hull with a clockwise winding. */ - static PhysicsBody* createPolygon(Point* points, int count); + static PhysicsBody* createPolygon(Point* points, int count, float density = 1); /** * @brief Create a body contains a EdgeSegment shape. @@ -84,37 +77,7 @@ public: */ static PhysicsBody* createEdgeChain(Point* points, int count, float border = 1); - /** - * @brief Attach a circle shape with body - */ - virtual PhysicsShapeCircle* addCircle(float radius, Point offset = Point(0, 0)); - /** - * @brief Attach a box shape with body - */ - virtual PhysicsShapeBox* addBox(Size size, Point offset = Point(0, 0)); - /** - * @brief Attach a polygon shape with body - */ - virtual PhysicsShapePolygon* addPolygon(Point* points, int count, Point offset = Point(0, 0)); - - /** - * @brief Attach a edge segment shape with body - */ - virtual PhysicsShapeEdgeSegment* addEdgeSegment(Point a, Point b, float border = 1); - /** - * @brief Attach a edge box shape with body - */ - virtual PhysicsShapeEdgeBox* addEdgeBox(Size size, float border = 1, Point offset = Point(0, 0)); - /** - * @brief Attach a edge polygon shape with body - * points is an array of Point structs defining a convex hull with a clockwise winding. - */ - virtual PhysicsShapeEdgePolygon* addEdgePolygon(Point* points, int count, float border = 1); - /** - * @brief Attach a edge chain shape with body - * points is an array of Point structs defining a convex hull with a clockwise winding. - */ - virtual PhysicsShapeEdgeChain* addEdgeChain(Point* points, int count, float border = 1); + virtual void addShape(PhysicsShape* shape); /** * @brief Applies a immediate force to body. @@ -137,6 +100,9 @@ public: */ virtual void applyTorque(float torque); + virtual void setVelocity(Point velocity); + virtual Point getVelocity(); + /* * @brief get the body shapes. */ @@ -226,11 +192,9 @@ public: protected: bool init(); - bool initStatic(); virtual void setPosition(Point position); virtual void setRotation(float rotation); - virtual void addShape(PhysicsShape* shape); protected: PhysicsBody(); diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index 1ce4cbb3b5..8aee1eacf9 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -46,8 +46,13 @@ PhysicsShape::PhysicsShape() : _body(nullptr) , _info(nullptr) , _type(Type::UNKNOWN) +, _area(0) +, _mass(0) +, _angularDamping(0) +, _density(0) , _tag(0) , _enable(true) +, _isAddToBody(false) { } @@ -71,6 +76,11 @@ bool PhysicsShape::init(PhysicsBody* body, Type type) return true; } +void PhysicsShape::setMass(float mass) +{ + +} + void PhysicsShape::setEnable(bool enable) { if (_enable != enable) @@ -173,11 +183,12 @@ PhysicsShapeEdgeSegment::~PhysicsShapeEdgeSegment() #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) // PhysicsShapeCircle -PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, Point offset/* = Point(0, 0)*/) +PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeCircle* shape = new PhysicsShapeCircle(); - if (shape && shape->init(body, radius, offset)) + if (shape && shape->init(body, radius, density, offset)) { + shape->autorelease(); return shape; } @@ -185,7 +196,7 @@ PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, return nullptr; } -bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { @@ -195,8 +206,15 @@ bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, Point offset /*= CC_BREAK_IF(shape == nullptr); + _density = density; + _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); + _mass = _density * _area; + if (_mass != 0) + { + _angularDamping = cpMomentForCircle(_density, 0, radius, PhysicsHelper::point2cpv(offset)); + } + _info->add(shape); - addToBody(); return true; } while (false); @@ -210,6 +228,7 @@ PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(PhysicsBody* body, Poin PhysicsShapeEdgeSegment* shape = new PhysicsShapeEdgeSegment(); if (shape && shape->init(body, a, b, border)) { + shape->autorelease(); return shape; } @@ -230,8 +249,10 @@ bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float bo CC_BREAK_IF(shape == nullptr); + _density = INFINITY; + _angularDamping = INFINITY; + _info->add(shape); - addToBody(); return true; } while (false); @@ -240,11 +261,12 @@ bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float bo } // PhysicsShapeBox -PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, Point offset/* = Point(0, 0)*/) +PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeBox* shape = new PhysicsShapeBox(); - if (shape && shape->init(body, size, offset)) + if (shape && shape->init(body, size, density, offset)) { + shape->autorelease(); return shape; } @@ -252,7 +274,7 @@ PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, Point off return nullptr; } -bool PhysicsShapeBox::init(PhysicsBody* body, Size size, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeBox::init(PhysicsBody* body, Size size, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { @@ -262,8 +284,15 @@ bool PhysicsShapeBox::init(PhysicsBody* body, Size size, Point offset /*= Point( CC_BREAK_IF(shape == nullptr); + _density = density; + _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(4, ((cpPolyShape*)shape)->verts)); + _mass = _density * _area; + if (_mass != 0) + { + _angularDamping = cpMomentForBox(_mass, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); + } + _info->add(shape); - addToBody(); return true; } while (false); @@ -272,11 +301,12 @@ bool PhysicsShapeBox::init(PhysicsBody* body, Size size, Point offset /*= Point( } // PhysicsShapeCircle -PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* points, int count, Point offset/* = Point(0, 0)*/) +PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* points, int count, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapePolygon* shape = new PhysicsShapePolygon(); - if (shape && shape->init(body, points, count, offset)) + if (shape && shape->init(body, points, count, density, offset)) { + shape->autorelease(); return shape; } @@ -284,7 +314,7 @@ PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* point return nullptr; } -bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, Point offset /*= Point(0, 0)*/) +bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { @@ -293,11 +323,19 @@ bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, Poin cpVect* vecs = new cpVect[count]; PhysicsHelper::points2cpvs(points, vecs, count); cpShape* shape = cpPolyShapeNew(bodyInfo()->body, count, vecs, PhysicsHelper::point2cpv(offset)); + CC_SAFE_DELETE(vecs); CC_BREAK_IF(shape == nullptr); + _density = density; + _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts)); + _mass = _density * _area; + if (_mass != 0) + { + _angularDamping = cpMomentForPoly(_mass, ((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts, PhysicsHelper::point2cpv(offset)); + } + _info->add(shape); - addToBody(); return true; } while (false); @@ -311,6 +349,7 @@ PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(PhysicsBody* body, Size size, f PhysicsShapeEdgeBox* shape = new PhysicsShapeEdgeBox(); if (shape && shape->init(body, size, border, offset)) { + shape->autorelease(); return shape; } @@ -344,7 +383,8 @@ bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1* } CC_BREAK_IF(i < 4); - addToBody(); + _mass = INFINITY; + _angularDamping = INFINITY; return true; } while (false); @@ -357,7 +397,8 @@ PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(PhysicsBody* body, Poin { PhysicsShapeEdgePolygon* shape = new PhysicsShapeEdgePolygon(); if (shape && shape->init(body, points, count, border)) - { + { + shape->autorelease(); return shape; } @@ -385,11 +426,13 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, cpShapeSetFriction(shape, 1.0f); _info->add(shape); } + CC_SAFE_DELETE(vec); + CC_BREAK_IF(i < count); - addToBody(); + _mass = INFINITY; + _angularDamping = INFINITY; - if (vec != nullptr) delete[] vec; return true; } while (false); @@ -404,6 +447,7 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(PhysicsBody* body, Point* p PhysicsShapeEdgeChain* shape = new PhysicsShapeEdgeChain(); if (shape && shape->init(body, points, count, border)) { + shape->autorelease(); return shape; } @@ -431,11 +475,12 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl cpShapeSetFriction(shape, 1.0f); _info->add(shape); } + if (vec != nullptr) delete[] vec; CC_BREAK_IF(i < count); - addToBody(); + _mass = INFINITY; + _angularDamping = INFINITY; - if (vec != nullptr) delete[] vec; return true; } while (false); diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index 4cc1da148b..b037eda1dc 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -58,10 +58,17 @@ public: public: inline PhysicsBody* getBody(){ return _body; } inline Type getType() { return _type; } + inline float getMass() { return _mass; } + void setMass(float mass); + inline float getArea() { return _area; } + inline float getDensity() { return _density; } + void setDensity(float density); + inline float getAngularDumping() { return _angularDamping; } inline void setTag(int tag) { _tag = tag; } inline int getTag() { return _tag; } void setEnable(bool enable); inline bool isEnable() { return _enable; } + void addToBody(); protected: bool init(PhysicsBody* body, Type type); @@ -71,8 +78,6 @@ protected: */ PhysicsBodyInfo* bodyInfo() const; - void addToBody(); - protected: PhysicsShape(); virtual ~PhysicsShape() = 0; @@ -81,8 +86,13 @@ protected: PhysicsBody* _body; PhysicsShapeInfo* _info; Type _type; + float _area; + float _mass; + float _angularDamping; + float _density; int _tag; bool _enable; + bool _isAddToBody; friend class PhysicsWorld; friend class PhysicsBody; @@ -91,9 +101,11 @@ protected: /** A circle shape */ class PhysicsShapeCircle : public PhysicsShape { +public: + static PhysicsShapeCircle* create(PhysicsBody* body, float radius, float density = 0, Point offset = Point(0, 0)); + protected: - static PhysicsShapeCircle* create(PhysicsBody* body, float radius, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, float radius, Point offset = Point(0, 0)); + bool init(PhysicsBody* body, float radius, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapeCircle(); @@ -105,9 +117,11 @@ protected: /** A box shape */ class PhysicsShapeBox : public PhysicsShape { +public: + static PhysicsShapeBox* create(PhysicsBody* body, Size size, float density = 0, Point offset = Point(0, 0)); + protected: - static PhysicsShapeBox* create(PhysicsBody* body, Size size, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, Size size, Point offset = Point(0, 0)); + bool init(PhysicsBody* body, Size size, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapeBox(); @@ -119,9 +133,11 @@ protected: /** A polygon shape */ class PhysicsShapePolygon : public PhysicsShape { +public: + static PhysicsShapePolygon* create(PhysicsBody* body, Point* points, int count, float density = 0, Point offset = Point(0, 0)); + protected: - static PhysicsShapePolygon* create(PhysicsBody* body, Point* points, int count, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, Point* points, int count, Point offset = Point(0, 0)); + bool init(PhysicsBody* body, Point* points, int count, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapePolygon(); @@ -133,8 +149,10 @@ protected: /** A segment shape */ class PhysicsShapeEdgeSegment : public PhysicsShape { -protected: +public: static PhysicsShapeEdgeSegment* create(PhysicsBody* body, Point a, Point b, float border = 1); + +protected: bool init(PhysicsBody* body, Point a, Point b, float border = 1); protected: diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index db4c3d46ab..c32219635e 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -5,7 +5,7 @@ USING_NS_CC; namespace { static std::function createFunctions[] = { - + CL(PhysicsDemoLogoSmash), CL(PhysicsDemoClickAdd), }; @@ -236,4 +236,111 @@ void PhysicsDemoClickAdd::onAcceleration(Acceleration* acc, Event* event) _scene->getPhysicsWorld()->setGravity(v); } #endif +} + +namespace +{ + static const int logo_width = 188; + static const int logo_height = 35; + static const int logo_row_length = 24; + static const char logo_image[] = + { + 15,-16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-64,15,63,-32,-2,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,31,-64,15,127,-125,-1,-128,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,127,-64,15,127,15,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-2, + 31,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,0,-4,63,-1,-32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-8,127,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,-1,-64,0,-8,-15,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-31,-1,-64,15,-8,-32, + -1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-15,-1,-64,9,-15,-32,-1,-32,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,31,-15,-1,-64,0,-15,-32,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,63,-7,-1,-64,9,-29,-32,127,-61,-16,63,15,-61,-1,-8,31,-16,15,-8,126,7,-31, + -8,31,-65,-7,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -4,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -2,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -2,63,-33,-1,-1,-32,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-33,-1,-1,-16,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-49,-1,-1,-8,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-49,-1,-1,-4,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-57,-1,-1,-2,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-1,-57,-1,-1,-1,9,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-119,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-55,-49,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-63,-1,-1,-1,-23,-49,-32,127,-57,-1,-1,-97,-25,-1,-1,63,-1,-1,-4,-1,15,-13, + -1,-1,-63,-1,-1,-1,-16,-49,-32,-1,-25,-1,-1,-97,-25,-1,-1,63,-33,-5,-4,-1,15, + -13,-1,-1,-64,-1,-9,-1,-7,-49,-32,-1,-25,-8,127,-97,-25,-1,-1,63,-33,-5,-4,-1, + 15,-13,-1,-1,-64,-1,-13,-1,-32,-49,-32,-1,-25,-8,127,-97,-25,-1,-2,63,-49,-13, + -4,-1,15,-13,-1,-1,-64,127,-7,-1,-119,-17,-15,-1,-25,-8,127,-97,-25,-1,-2,63, + -49,-13,-4,-1,15,-13,-3,-1,-64,127,-8,-2,15,-17,-1,-1,-25,-8,127,-97,-25,-1, + -8,63,-49,-13,-4,-1,15,-13,-3,-1,-64,63,-4,120,0,-17,-1,-1,-25,-8,127,-97,-25, + -8,0,63,-57,-29,-4,-1,15,-13,-4,-1,-64,63,-4,0,15,-17,-1,-1,-25,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,-1,-64,31,-2,0,0,103,-1,-1,-57,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,127,-64,31,-2,0,15,103,-1,-1,-57,-8,127, + -97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,127,-64,15,-8,0,0,55,-1,-1,-121,-8, + 127,-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,63,-64,15,-32,0,0,23,-1,-2,3,-16, + 63,15,-61,-16,0,31,-127,-127,-8,31,-1,-127,-8,31,-128,7,-128,0,0}; + + static inline int + get_pixel(int x, int y) + { + return (logo_image[(x>>3) + y*logo_row_length]>>(~x&0x7)) & 1; + } + +#define RAND_MAX 0x7fffffff + static inline float + frand(void) + { + return rand()/RAND_MAX; + } +} + +Node* PhysicsDemoLogoSmash::makeBall(float x, float y) +{ + Sprite* ball = Sprite::create("Images/ball.png"); + ball->setScale(0.1); + + PhysicsBody* body = PhysicsBody::createCircle(0.95); + body->setDynamic(false); + ball->setPhysicsBody(body); + + ball->setPosition(Point(x, y)); + + return ball; +} + +void PhysicsDemoLogoSmash::onEnter() +{ + PhysicsDemo::onEnter(); + _draw = DrawNode::create(); + + //addChild(makeBall(200, 200)); + for (int y = 0; y < logo_height; ++y) + { + for (int x = 0; x < logo_width; ++x) + { + if (get_pixel(x, y)) + { + float x_jitter = 0.05*frand(); + float y_jitter = 0.05*frand(); + + addChild(makeBall(2*(x - logo_width/2 + x_jitter) + VisibleRect::getVisibleRect().size.width/2, + 2*(logo_height-y + y_jitter) + VisibleRect::getVisibleRect().size.height/2 - logo_height/2)); + } + } + } + + + Sprite* bullet = Sprite::create("Images/ball.png"); + bullet->setScale(0.2); + + PhysicsBody* body = PhysicsBody::createCircle(3); + body->setDynamic(false); + body->setVelocity(Point(400, 0)); + bullet->setPhysicsBody(body); + + bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2)); +} + +std::string PhysicsDemoLogoSmash::title() +{ + return "Logo Smash"; } \ No newline at end of file diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h index 5acb33e855..cf63471998 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h @@ -6,6 +6,13 @@ #include "../BaseTest.h" +class PhysicsTestScene : public TestScene +{ +public: + virtual bool initTest() override; + virtual void runThisTest(); +}; + class PhysicsDemo : public BaseTest { protected: @@ -15,9 +22,9 @@ public: PhysicsDemo(); virtual ~PhysicsDemo(); - virtual void onEnter(); - virtual std::string title(); - virtual std::string subtitle(); + virtual void onEnter() override; + virtual std::string title() override; + virtual std::string subtitle() override; void restartCallback(Object* sender); void nextCallback(Object* sender); @@ -27,24 +34,29 @@ public: class PhysicsDemoClickAdd : public PhysicsDemo { -private: - Texture2D* _spriteTexture; // weak ref - public: - void onEnter(); - std::string subtitle(); + void onEnter() override; + std::string subtitle() override; void addNewSpriteAtPosition(Point p); - void onTouchesEnded(const std::vector& touches, Event* event); - void onAcceleration(Acceleration* acc, Event* event); + void onTouchesEnded(const std::vector& touches, Event* event) override; + void onAcceleration(Acceleration* acc, Event* event) override; + +private: + Texture2D* _spriteTexture; // weak ref }; -class PhysicsTestScene : public TestScene +class PhysicsDemoLogoSmash : public PhysicsDemo { public: - virtual bool initTest() override; - virtual void runThisTest(); + void onEnter() override; + std::string title() override; + + Node* makeBall(float x, float y); + +private: + DrawNode* _draw; }; #endif From 35259588a3aff11981e3bece1ee00220961d21d1 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Mon, 30 Sep 2013 21:48:25 +0800 Subject: [PATCH 010/116] issue #2771: fix some bugs in PhysicsShape --- cocos2dx/physics/CCPhysicsShape.cpp | 7 ++----- cocos2dx/physics/CCPhysicsShape.h | 1 + .../TestCpp/Classes/PhysicsTest/PhysicsTest.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index 8aee1eacf9..35edfb5f1e 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -208,11 +208,8 @@ bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, float density/* = _density = density; _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); - _mass = _density * _area; - if (_mass != 0) - { - _angularDamping = cpMomentForCircle(_density, 0, radius, PhysicsHelper::point2cpv(offset)); - } + _mass = _density == INFINITY ? INFINITY : _density * _area; + _angularDamping = _mass == INFINITY ? INFINITY : cpMomentForCircle(_mass, 0, radius, PhysicsHelper::point2cpv(offset)); _info->add(shape); diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index b037eda1dc..3d431f96e7 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -64,6 +64,7 @@ public: inline float getDensity() { return _density; } void setDensity(float density); inline float getAngularDumping() { return _angularDamping; } + void setAngularDumping(float angularDumping); inline void setTag(int tag) { _tag = tag; } inline int getTag() { return _tag; } void setEnable(bool enable); diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index c32219635e..ebab929dec 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -279,15 +279,13 @@ namespace 127,-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,63,-64,15,-32,0,0,23,-1,-2,3,-16, 63,15,-61,-16,0,31,-127,-127,-8,31,-1,-127,-8,31,-128,7,-128,0,0}; - static inline int - get_pixel(int x, int y) + static inline int get_pixel(int x, int y) { return (logo_image[(x>>3) + y*logo_row_length]>>(~x&0x7)) & 1; } #define RAND_MAX 0x7fffffff - static inline float - frand(void) + static inline float frand(void) { return rand()/RAND_MAX; } @@ -299,7 +297,7 @@ Node* PhysicsDemoLogoSmash::makeBall(float x, float y) ball->setScale(0.1); PhysicsBody* body = PhysicsBody::createCircle(0.95); - body->setDynamic(false); + //body->setDynamic(false); ball->setPhysicsBody(body); ball->setPosition(Point(x, y)); @@ -312,6 +310,7 @@ void PhysicsDemoLogoSmash::onEnter() PhysicsDemo::onEnter(); _draw = DrawNode::create(); + _scene->getPhysicsWorld()->setGravity(Point(0, 0)); //addChild(makeBall(200, 200)); for (int y = 0; y < logo_height; ++y) { @@ -330,14 +329,15 @@ void PhysicsDemoLogoSmash::onEnter() Sprite* bullet = Sprite::create("Images/ball.png"); - bullet->setScale(0.2); + bullet->setScale(0.5); - PhysicsBody* body = PhysicsBody::createCircle(3); - body->setDynamic(false); + PhysicsBody* body = PhysicsBody::createCircle(3, INFINITY); body->setVelocity(Point(400, 0)); bullet->setPhysicsBody(body); bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2)); + + addChild(bullet); } std::string PhysicsDemoLogoSmash::title() From 5acac436f90506a023b94421c41c8c3a17f93fbc Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Tue, 8 Oct 2013 10:11:52 +0800 Subject: [PATCH 011/116] issues #2677:Use CoreMotion's API to replace UIAccelerometer. --- cocos2dx/platform/ios/CCDevice.mm | 26 +++++++++++-------- .../project.pbxproj.REMOVED.git-id | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cocos2dx/platform/ios/CCDevice.mm b/cocos2dx/platform/ios/CCDevice.mm index 6ced352414..f678244da7 100644 --- a/cocos2dx/platform/ios/CCDevice.mm +++ b/cocos2dx/platform/ios/CCDevice.mm @@ -6,13 +6,13 @@ #import // Accelerometer -#import -#import -#import +#include +#import @interface CCAccelerometerDispatcher : NSObject { cocos2d::Acceleration *_acceleration; + CMMotionManager *_motionManager; } + (id) sharedAccelerometerDispather; @@ -38,6 +38,7 @@ static CCAccelerometerDispatcher* s_pAccelerometerDispatcher; - (id) init { _acceleration = new cocos2d::Acceleration(); + _motionManager = [[CMMotionManager alloc] init]; return self; } @@ -45,6 +46,7 @@ static CCAccelerometerDispatcher* s_pAccelerometerDispatcher; { s_pAccelerometerDispatcher = nullptr; delete _acceleration; + [_motionManager release]; [super dealloc]; } @@ -52,25 +54,27 @@ static CCAccelerometerDispatcher* s_pAccelerometerDispatcher; { if (isEnabled) { - [[UIAccelerometer sharedAccelerometer] setDelegate:self]; + [_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { + [self accelerometer:accelerometerData]; + }]; } else { - [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; + [_motionManager stopAccelerometerUpdates]; } } -(void) setAccelerometerInterval:(float)interval { - [[UIAccelerometer sharedAccelerometer] setUpdateInterval:interval]; + _motionManager.accelerometerUpdateInterval = interval; } -- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration +- (void)accelerometer:(CMAccelerometerData *)accelerometerData { - _acceleration->x = acceleration.x; - _acceleration->y = acceleration.y; - _acceleration->z = acceleration.z; - _acceleration->timestamp = acceleration.timestamp; + _acceleration->x = accelerometerData.acceleration.x; + _acceleration->y = accelerometerData.acceleration.y; + _acceleration->z = accelerometerData.acceleration.z; + _acceleration->timestamp = accelerometerData.timestamp; double tmp = _acceleration->x; diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index efbf8806ae..dc39ae6bd3 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -b759f56a07f242b20e9c96f2a6cd49c4b5c9dc9b \ No newline at end of file +d846dfb9965fecfad1f6fe6190516035158c4d53 \ No newline at end of file From 8dc55b37732e8a2cbe759119063738957627dab7 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Tue, 8 Oct 2013 11:08:45 +0800 Subject: [PATCH 012/116] issues #2677:Use CoreMotion's API to replace UIAccelerometer. --- .../proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj | 4 ++++ .../proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj | 4 ++++ .../proj.ios_mac/HelloLua.xcodeproj/project.pbxproj | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj b/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj index 7e027bca7a..3cb7edab03 100644 --- a/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj +++ b/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ D44C620C132DFF330009C878 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620B132DFF330009C878 /* OpenAL.framework */; }; D44C620E132DFF430009C878 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620D132DFF430009C878 /* AVFoundation.framework */; }; D44C6210132DFF4E0009C878 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D44C620F132DFF4E0009C878 /* AudioToolbox.framework */; }; + D6B0611B1803AB670077942B /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B0611A1803AB670077942B /* CoreMotion.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -294,6 +295,7 @@ D44C620B132DFF330009C878 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; D44C620D132DFF430009C878 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; D44C620F132DFF4E0009C878 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + D6B0611A1803AB670077942B /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -301,6 +303,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D6B0611B1803AB670077942B /* CoreMotion.framework in Frameworks */, 1AF4C2F417865DCB00122817 /* libbox2d iOS.a in Frameworks */, 1AF4C2F517865DCB00122817 /* libchipmunk iOS.a in Frameworks */, 1AF4C2F617865DCB00122817 /* libcocos2dx iOS.a in Frameworks */, @@ -419,6 +422,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + D6B0611A1803AB670077942B /* CoreMotion.framework */, 503AE11A17EB9C5A00D1A890 /* IOKit.framework */, 503AE11117EB99EE00D1A890 /* libcurl.dylib */, 5087E78A17EB975400C73F5D /* OpenGL.framework */, diff --git a/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj b/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj index 0601fd183a..9958c7a786 100644 --- a/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj +++ b/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj @@ -95,6 +95,7 @@ A92275501517C094001B78AA /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A922754F1517C094001B78AA /* CoreGraphics.framework */; }; D454520C156E22BD00887EB5 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D454520B156E22BD00887EB5 /* libz.dylib */; }; D4545227156E28EF00887EB5 /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4545215156E28EF00887EB5 /* AppDelegate.cpp */; }; + D6B061241803AB9F0077942B /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B061231803AB9F0077942B /* CoreMotion.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -276,6 +277,7 @@ D454520B156E22BD00887EB5 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; D4545215156E28EF00887EB5 /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = ""; }; D4545216156E28EF00887EB5 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + D6B061231803AB9F0077942B /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -307,6 +309,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D6B061241803AB9F0077942B /* CoreMotion.framework in Frameworks */, 1AF4C33317865EC500122817 /* libchipmunk iOS.a in Frameworks */, 1AF4C33417865EC500122817 /* libcocos2dx iOS.a in Frameworks */, 1AF4C33517865EC500122817 /* libcocos2dx-extensions iOS.a in Frameworks */, @@ -437,6 +440,7 @@ A92275401517C094001B78AA /* Frameworks */ = { isa = PBXGroup; children = ( + D6B061231803AB9F0077942B /* CoreMotion.framework */, 502380DB17EBB88200990C9B /* libcurl.dylib */, 509D4AEA17EBB82600697056 /* IOKit.framework */, 509D4AE817EBB82000697056 /* AppKit.framework */, diff --git a/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj b/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj index 2b9b653096..8403e89e8a 100644 --- a/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj +++ b/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj @@ -101,6 +101,7 @@ 50D7C97417EBBEF7005D0B91 /* libcocos2dx-extensions Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C3CF1786631700122817 /* libcocos2dx-extensions Mac.a */; }; 50D7C97517EBBEF7005D0B91 /* libCocosDenshion Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C3D51786631700122817 /* libCocosDenshion Mac.a */; }; 50D7C97617EBBEF7005D0B91 /* libluabindings Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C3D91786631700122817 /* libluabindings Mac.a */; }; + D6B061351803AC000077942B /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B061341803AC000077942B /* CoreMotion.framework */; }; F293B3CD15EB7BE500256477 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3CC15EB7BE500256477 /* QuartzCore.framework */; }; F293B3D115EB7BE500256477 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D015EB7BE500256477 /* OpenAL.framework */; }; F293B3D315EB7BE500256477 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D215EB7BE500256477 /* AudioToolbox.framework */; }; @@ -285,6 +286,7 @@ 50D7C96B17EBBEDF005D0B91 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; 50D7C96D17EBBEE6005D0B91 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 50D7C96F17EBBEEC005D0B91 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + D6B061341803AC000077942B /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; }; F293B3C815EB7BE500256477 /* HelloLua iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HelloLua iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; F293B3CC15EB7BE500256477 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; F293B3CE15EB7BE500256477 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -326,6 +328,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D6B061351803AC000077942B /* CoreMotion.framework in Frameworks */, 50D7C96517EBBECA005D0B91 /* libbox2d iOS.a in Frameworks */, 50D7C96617EBBECA005D0B91 /* libchipmunk iOS.a in Frameworks */, 50D7C96717EBBECA005D0B91 /* libcocos2dx iOS.a in Frameworks */, @@ -462,6 +465,7 @@ F293B3CB15EB7BE500256477 /* Frameworks */ = { isa = PBXGroup; children = ( + D6B061341803AC000077942B /* CoreMotion.framework */, 50D7C96F17EBBEEC005D0B91 /* IOKit.framework */, 50D7C96D17EBBEE6005D0B91 /* AppKit.framework */, 50D7C96B17EBBEDF005D0B91 /* OpenGL.framework */, From 44a63bb885ea871c4fc09bd74d85db2ce9105244 Mon Sep 17 00:00:00 2001 From: "Huabing.Xu" Date: Tue, 8 Oct 2013 11:48:57 +0800 Subject: [PATCH 013/116] closed #2425: fix hole demo test error, we should use GLprogram before we set uniform to them --- cocos2dx/misc_nodes/CCClippingNode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cocos2dx/misc_nodes/CCClippingNode.cpp b/cocos2dx/misc_nodes/CCClippingNode.cpp index 5d3aeb741e..7b797617cb 100644 --- a/cocos2dx/misc_nodes/CCClippingNode.cpp +++ b/cocos2dx/misc_nodes/CCClippingNode.cpp @@ -311,6 +311,7 @@ void ClippingNode::visit() GLProgram *program = ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST); GLint alphaValueLocation = glGetUniformLocation(program->getProgram(), GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE); // set our alphaThreshold + program->use(); program->setUniformLocationWith1f(alphaValueLocation, _alphaThreshold); // we need to recursively apply this shader to all the nodes in the stencil node // XXX: we should have a way to apply shader to all nodes without having to do this From 5a5dd2da14be24c7e94b709efb8ce7b4861f0f9d Mon Sep 17 00:00:00 2001 From: LinWenhai Date: Tue, 8 Oct 2013 13:44:35 +0800 Subject: [PATCH 014/116] Update CCDevice.mm --- cocos2dx/platform/ios/CCDevice.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos2dx/platform/ios/CCDevice.mm b/cocos2dx/platform/ios/CCDevice.mm index f678244da7..e84eb4196d 100644 --- a/cocos2dx/platform/ios/CCDevice.mm +++ b/cocos2dx/platform/ios/CCDevice.mm @@ -6,7 +6,7 @@ #import // Accelerometer -#include +#import #import @interface CCAccelerometerDispatcher : NSObject From 508654738ad263e652fbf2c06186b1a3f102c623 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Tue, 8 Oct 2013 15:45:13 +0800 Subject: [PATCH 015/116] issue #2768:Modify armature test sample and skip some functions to lua --- .../TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua | 2 +- tools/tolua/cocos2dx_extension.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua index 7374719740..66a224d9e2 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ArmatureTest.lua @@ -32,7 +32,7 @@ end function ArmatureTestScene:runThisTest() cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/TestBone0.png", "armature/TestBone0.plist", "armature/TestBone.json") - cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/Cowboy0.png", "armature/Cowboy0.plist", "armature/Cowboy.json") + cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/Cowboy0.png", "armature/Cowboy0.plist", "armature/Cowboy.ExportJson") cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/knight.png", "armature/knight.plist", "armature/knight.xml") cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/weapon.png", "armature/weapon.plist", "armature/weapon.xml") cc.ArmatureDataManager:getInstance():addArmatureFileInfo("armature/robot.png", "armature/robot.plist", "armature/robot.xml") diff --git a/tools/tolua/cocos2dx_extension.ini b/tools/tolua/cocos2dx_extension.ini index 5f35f20cbe..ce914cf508 100644 --- a/tools/tolua/cocos2dx_extension.ini +++ b/tools/tolua/cocos2dx_extension.ini @@ -47,7 +47,7 @@ skip = CCBReader::[^CCBReader$ addOwnerCallbackName isJSControlled readByte getC ControlUtils::[*], ControlSwitchSprite::[*], ArmatureDataManager::[CCArmatureDataManager ~CCArmatureDataManager], - Armature::[createBone updateBlendType getCPBody setCPBody (s|g)etBlendFunc], + Armature::[createBone updateBlendType getCPBody setCPBody (s|g)etBlendFunc getShapeList ^getBody$], Skin::[getSkinData setSkinData], ArmatureAnimation::[updateHandler updateFrameData frameEvent], Bone::[(s|g)etIgnoreMovementBoneData] From 20971b0ad2cec75fba2facd4fa5ac8aa249607f1 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Tue, 8 Oct 2013 15:57:34 +0800 Subject: [PATCH 016/116] issues #2895:Synchronize JSB from master to developer --- cocos2dx/base_nodes/CCNode.cpp | 8 + cocos2dx/base_nodes/CCNode.h | 9 + .../javascript/bindings/XMLHTTPRequest.cpp | 2 +- .../bindings/js/jsb_cocosbuilder.js | 4 +- .../jsb_cocos2dx_extension_manual.cpp | 216 ++++++++++++++++++ tools/tojs/cocos2dx.ini | 14 +- tools/tojs/cocos2dx_extension.ini | 16 +- 7 files changed, 253 insertions(+), 16 deletions(-) diff --git a/cocos2dx/base_nodes/CCNode.cpp b/cocos2dx/base_nodes/CCNode.cpp index f4547bb1fa..8169029ebd 100644 --- a/cocos2dx/base_nodes/CCNode.cpp +++ b/cocos2dx/base_nodes/CCNode.cpp @@ -301,6 +301,14 @@ float Node::getScaleX() const return _scaleX; } +/// scale setter +void Node::setScale(float scaleX,float scaleY) +{ + _scaleX = scaleX; + _scaleY = scaleY; + _transformDirty = _inverseDirty = true; +} + /// scaleX setter void Node::setScaleX(float newScaleX) { diff --git a/cocos2dx/base_nodes/CCNode.h b/cocos2dx/base_nodes/CCNode.h index e335ff11fd..b84786126d 100644 --- a/cocos2dx/base_nodes/CCNode.h +++ b/cocos2dx/base_nodes/CCNode.h @@ -288,6 +288,15 @@ public: */ virtual float getScale() const; + /** + * Changes both X and Y scale factor of the node. + * + * 1.0 is the default scale factor. It modifies the X and Y scale at the same time. + * + * @param scaleX The scale factor on X axis. + * @param scaleY The scale factor on Y axis. + */ + virtual void setScale(float scaleX,float scaleY); /** * Changes the position (x,y) of the node in OpenGL coordinates diff --git a/scripting/javascript/bindings/XMLHTTPRequest.cpp b/scripting/javascript/bindings/XMLHTTPRequest.cpp index a096756af5..e334833fa3 100644 --- a/scripting/javascript/bindings/XMLHTTPRequest.cpp +++ b/scripting/javascript/bindings/XMLHTTPRequest.cpp @@ -209,7 +209,7 @@ void MinXmlHttpRequest::handle_requestResponse(cocos2d::extension::HttpClient *s _status = 200; _readyState = DONE; _data << concatenated; - + _dataSize = buffer->size(); } else { diff --git a/scripting/javascript/bindings/js/jsb_cocosbuilder.js b/scripting/javascript/bindings/js/jsb_cocosbuilder.js index f748486286..7e70b8c70e 100644 --- a/scripting/javascript/bindings/js/jsb_cocosbuilder.js +++ b/scripting/javascript/bindings/js/jsb_cocosbuilder.js @@ -148,12 +148,12 @@ cc.BuilderReader.load = function(file, owner, parentSize) if (callbackType == 1) // Document callback { var callfunc = cc.CallFunc.create(controller[callbackName], controller); - animationManager.setCallFuncForJSCallbackNamed(callfunc, keyframeCallbacks[j]); + animationManager.setCallFunc(callfunc, keyframeCallbacks[j]); } else if (callbackType == 2 && owner) // Owner callback { var callfunc = cc.CallFunc.create(owner[callbackName], owner); - animationManager.setCallFuncForJSCallbackNamed(callfunc, keyframeCallbacks[j]); + animationManager.setCallFunc(callfunc, keyframeCallbacks[j]); } } diff --git a/scripting/javascript/bindings/jsb_cocos2dx_extension_manual.cpp b/scripting/javascript/bindings/jsb_cocos2dx_extension_manual.cpp index abaf07a2f7..3ec02a7d86 100644 --- a/scripting/javascript/bindings/jsb_cocos2dx_extension_manual.cpp +++ b/scripting/javascript/bindings/jsb_cocos2dx_extension_manual.cpp @@ -12,6 +12,7 @@ USING_NS_CC; USING_NS_CC_EXT; +using namespace extension::armature; class JSB_ScrollViewDelegate : public Object @@ -779,9 +780,218 @@ static JSBool js_cocos2dx_CCControl_removeTargetWithActionForControlEvents(JSCon return JS_FALSE; } +class JSArmatureWrapper: public JSCallbackWrapper { +public: + JSArmatureWrapper(); + virtual ~JSArmatureWrapper(); + + virtual void setJSCallbackThis(jsval thisObj); + + void movementCallbackFunc(cocos2d::extension::armature::Armature * pArmature, cocos2d::extension::armature::MovementEventType pMovementEventType, const char *pMovementId); + void frameCallbackFunc(cocos2d::extension::Bone *pBone, const char *frameEventName, int originFrameIndex, int currentFrameIndex); + void addArmatureFileInfoAsyncCallbackFunc(float percent); + +private: + bool m_bNeedUnroot; +}; + +JSArmatureWrapper::JSArmatureWrapper() + : m_bNeedUnroot(false) +{ + +} + +JSArmatureWrapper::~JSArmatureWrapper() +{ + if (m_bNeedUnroot) + { + JSObject *thisObj = JSVAL_TO_OBJECT(_jsThisObj); + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JS_RemoveObjectRoot(cx, &thisObj); + } +} + +void JSArmatureWrapper::setJSCallbackThis(jsval _jsThisObj) +{ + JSCallbackWrapper::setJSCallbackThis(_jsThisObj); + + JSObject *thisObj = JSVAL_TO_OBJECT(_jsThisObj); + js_proxy *p = jsb_get_js_proxy(thisObj); + if (!p) + { + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JS_AddObjectRoot(cx, &thisObj); + m_bNeedUnroot = true; + } +} + +void JSArmatureWrapper::movementCallbackFunc(cocos2d::extension::armature::Armature *pArmature, cocos2d::extension::armature::MovementEventType pMovementEventType, const char *pMovementId) +{ + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject *thisObj = JSVAL_IS_VOID(_jsThisObj) ? NULL : JSVAL_TO_OBJECT(_jsThisObj); + js_proxy_t *proxy = js_get_or_create_proxy(cx, pArmature); + jsval retval; + if (_jsCallback != JSVAL_VOID) + { + int movementEventType = (int)pMovementEventType; + jsval movementVal = INT_TO_JSVAL(movementEventType); + + jsval idVal = c_string_to_jsval(cx, pMovementId); + + jsval valArr[3]; + valArr[0] = OBJECT_TO_JSVAL(proxy->obj); + valArr[1] = movementVal; + valArr[2] = idVal; + + JS_AddValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, _jsCallback, 3, valArr, &retval); + JS_RemoveValueRoot(cx, valArr); + } +} + +void JSArmatureWrapper::addArmatureFileInfoAsyncCallbackFunc(float percent) +{ + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject *thisObj = JSVAL_IS_VOID(_jsThisObj) ? NULL : JSVAL_TO_OBJECT(_jsThisObj); + jsval retval; + if (_jsCallback != JSVAL_VOID) + { + jsval percentVal = DOUBLE_TO_JSVAL(percent); + + JS_AddValueRoot(cx, &percentVal); + JS_CallFunctionValue(cx, thisObj, _jsCallback, 1, &percentVal, &retval); + JS_RemoveValueRoot(cx, &percentVal); + } +} + + +void JSArmatureWrapper::frameCallbackFunc(cocos2d::extension::Bone *pBone, const char *frameEventName, int originFrameIndex, int currentFrameIndex) +{ + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject *thisObj = JSVAL_IS_VOID(_jsThisObj) ? NULL : JSVAL_TO_OBJECT(_jsThisObj); + js_proxy_t *proxy = js_get_or_create_proxy(cx, pBone); + jsval retval; + if (_jsCallback != JSVAL_VOID) + { + jsval nameVal = c_string_to_jsval(cx, frameEventName); + jsval originIndexVal = INT_TO_JSVAL(originFrameIndex); + jsval currentIndexVal = INT_TO_JSVAL(currentFrameIndex); + + jsval valArr[4]; + valArr[0] = OBJECT_TO_JSVAL(proxy->obj); + valArr[1] = nameVal; + valArr[2] = originIndexVal; + valArr[3] = currentIndexVal; + + JS_AddValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, _jsCallback, 4, valArr, &retval); + JS_RemoveValueRoot(cx, valArr); + } +} + +static JSBool js_cocos2dx_ArmatureAnimation_setMovementEventCallFunc(JSContext *cx, uint32_t argc, jsval *vp) +{ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + js_proxy_t *proxy = jsb_get_js_proxy(obj); + cocos2d::extension::armature::ArmatureAnimation* cobj = (cocos2d::extension::armature::ArmatureAnimation *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if (argc == 2) { + jsval *argv = JS_ARGV(cx, vp); + + JSArmatureWrapper *tmpObj = new JSArmatureWrapper(); + tmpObj->autorelease(); + + tmpObj->setJSCallbackFunc(argv[0]); + tmpObj->setJSCallbackThis(argv[1]); + + cobj->setMovementEventCallFunc(tmpObj, movementEvent_selector(JSArmatureWrapper::movementCallbackFunc)); + + return JS_TRUE; + } + JS_ReportError(cx, "Invalid number of arguments"); + return JS_FALSE; +} + +static JSBool js_cocos2dx_ArmatureAnimation_setFrameEventCallFunc(JSContext *cx, uint32_t argc, jsval *vp) +{ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + js_proxy_t *proxy = jsb_get_js_proxy(obj); + cocos2d::extension::armature::ArmatureAnimation* cobj = (cocos2d::extension::armature::ArmatureAnimation *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if (argc == 2) { + jsval *argv = JS_ARGV(cx, vp); + + JSArmatureWrapper *tmpObj = new JSArmatureWrapper(); + tmpObj->autorelease(); + + tmpObj->setJSCallbackFunc(argv[0]); + tmpObj->setJSCallbackThis(argv[1]); + + cobj->setFrameEventCallFunc(tmpObj, frameEvent_selector(JSArmatureWrapper::frameCallbackFunc)); + + return JS_TRUE; + } + JS_ReportError(cx, "Invalid number of arguments"); + return JS_FALSE; +} + +static JSBool jsb_Animation_addArmatureFileInfoAsyncCallFunc(JSContext *cx, uint32_t argc, jsval *vp) +{ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + js_proxy_t *proxy = jsb_get_js_proxy(obj); + cocos2d::extension::armature::ArmatureDataManager* cobj = (cocos2d::extension::armature::ArmatureDataManager *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if (argc == 3) { + jsval *argv = JS_ARGV(cx, vp); + + JSArmatureWrapper *tmpObj = new JSArmatureWrapper(); + tmpObj->autorelease(); + + tmpObj->setJSCallbackFunc(argv[2]); + tmpObj->setJSCallbackThis(argv[1]); + + std::string ret; + jsval_to_std_string(cx, argv[0], &ret); + + cobj->addArmatureFileInfoAsync(ret.c_str(), tmpObj, schedule_selector(JSArmatureWrapper::addArmatureFileInfoAsyncCallbackFunc)); + + return JS_TRUE; + } + + if(argc == 5){ + jsval *argv = JS_ARGV(cx, vp); + + JSArmatureWrapper *tmpObj = new JSArmatureWrapper(); + tmpObj->autorelease(); + + tmpObj->setJSCallbackFunc(argv[4]); + tmpObj->setJSCallbackThis(argv[3]); + + std::string imagePath; + jsval_to_std_string(cx ,argv[0] , &imagePath); + + std::string plistPath; + jsval_to_std_string(cx ,argv[1] , &plistPath); + + std::string configFilePath; + jsval_to_std_string(cx ,argv[2] , &configFilePath); + + cobj->addArmatureFileInfoAsync(imagePath.c_str(), plistPath.c_str(), configFilePath.c_str(), tmpObj, schedule_selector(JSArmatureWrapper::addArmatureFileInfoAsyncCallbackFunc)); + + return JS_TRUE; + } + JS_ReportError(cx, "Invalid number of arguments"); + return JS_FALSE; +} + extern JSObject* jsb_ScrollView_prototype; extern JSObject* jsb_TableView_prototype; extern JSObject* jsb_EditBox_prototype; +extern JSObject* jsb_ArmatureAnimation_prototype; +extern JSObject* jsb_ArmatureDataManager_prototype; extern JSObject* jsb_Control_prototype; void register_all_cocos2dx_extension_manual(JSContext* cx, JSObject* global) @@ -793,6 +1003,12 @@ void register_all_cocos2dx_extension_manual(JSContext* cx, JSObject* global) JS_DefineFunction(cx, jsb_Control_prototype, "addTargetWithActionForControlEvents", js_cocos2dx_CCControl_addTargetWithActionForControlEvents, 3, JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(cx, jsb_Control_prototype, "removeTargetWithActionForControlEvents", js_cocos2dx_CCControl_removeTargetWithActionForControlEvents, 3, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(cx, jsb_ArmatureAnimation_prototype, "setMovementEventCallFunc", js_cocos2dx_ArmatureAnimation_setMovementEventCallFunc, 2, JSPROP_READONLY | JSPROP_PERMANENT); + + JS_DefineFunction(cx, jsb_ArmatureAnimation_prototype, "setFrameEventCallFunc", js_cocos2dx_ArmatureAnimation_setFrameEventCallFunc, 2, JSPROP_READONLY | JSPROP_PERMANENT); + + JS_DefineFunction(cx, jsb_ArmatureDataManager_prototype, "addArmatureFileInfoAsync", jsb_Animation_addArmatureFileInfoAsyncCallFunc, 3, JSPROP_READONLY | JSPROP_PERMANENT); + JSObject *tmpObj = JSVAL_TO_OBJECT(anonEvaluate(cx, global, "(function () { return cc.TableView; })()")); JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_CCTableView_create, 3, JSPROP_READONLY | JSPROP_PERMANENT); } \ No newline at end of file diff --git a/tools/tojs/cocos2dx.ini b/tools/tojs/cocos2dx.ini index 9e2a2399af..7001e2f1f6 100644 --- a/tools/tojs/cocos2dx.ini +++ b/tools/tojs/cocos2dx.ini @@ -26,7 +26,7 @@ headers = %(cocosdir)s/cocos2dx/include/cocos2d.h %(cocosdir)s/CocosDenshion/inc # what classes to produce code for. You can use regular expressions here. When testing the regular # expression, it will be enclosed in "^$", like this: "^Menu*$". -classes = Sprite.* Scene Node.* Director Layer.* Menu.* Touch .*Action.* Move.* Rotate.* Blink.* Tint.* Sequence Repeat.* Fade.* Ease.* Scale.* Transition.* Spawn Animat.* Flip.* Delay.* Skew.* Jump.* Place.* Show.* Progress.* PointArray ToggleVisibility.* RemoveSelf Hide Particle.* Label.* Atlas.* TextureCache.* Texture2D Cardinal.* CatmullRom.* ParallaxNode TileMap.* TMX.* CallFunc RenderTexture GridAction Grid3DAction GridBase$ .+Grid Shaky3D Waves3D FlipX3D FlipY3D Speed ActionManager Set Data SimpleAudioEngine Scheduler Timer Orbit.* Follow.* Bezier.* CardinalSpline.* Camera.* DrawNode .*3D$ Liquid$ Waves$ ShuffleTiles$ TurnOffTiles$ Split.* Twirl$ FileUtils$ GLProgram ShaderCache Application ClippingNode MotionStreak +classes = Sprite.* Scene Node.* Director Layer.* Menu.* Touch .*Action.* Move.* Rotate.* Blink.* Tint.* Sequence Repeat.* Fade.* Ease.* Scale.* Transition.* Spawn Animat.* Flip.* Delay.* Skew.* Jump.* Place.* Show.* Progress.* PointArray ToggleVisibility.* RemoveSelf Hide Particle.* Label.* Atlas.* TextureCache.* Texture2D Cardinal.* CatmullRom.* ParallaxNode TileMap.* TMX.* CallFunc RenderTexture GridAction Grid3DAction GridBase$ .+Grid Shaky3D Waves3D FlipX3D FlipY3D Speed ActionManager Set Data SimpleAudioEngine Scheduler Timer Orbit.* Follow.* Bezier.* CardinalSpline.* Camera.* DrawNode .*3D$ Liquid$ Waves$ ShuffleTiles$ TurnOffTiles$ Split.* Twirl$ FileUtils$ GLProgram ShaderCache Application ClippingNode MotionStreak TextFieldTTF EGLViewProtocol EGLView # what should we skip? in the format ClassName::[function function] # ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also @@ -49,7 +49,8 @@ skip = Node::[^setPosition$ getGrid setGLServerState description getUserObject . Menu.*::[.*Target getSubItems create initWithItems alignItemsInRows alignItemsInColumns], MenuItem.*::[create setCallback initWithCallback], Copying::[*], - .*Protocol::[*], + LabelProtocol::[*], + LabelTextFormatProtocol::[*], .*Delegate::[*], PoolManager::[*], Texture2D::[initWithPVRTCData addPVRTCImage releaseData setTexParameters initWithData keepData], @@ -67,7 +68,8 @@ skip = Node::[^setPosition$ getGrid setGLServerState description getUserObject . ScriptEngineManager::[*], KeypadHandler::[*], Invocation::[*], - EGLView::[*], + EGLView::[end swapBuffers], + EGLViewProtocol::[(?!setDesignResolutionSize|getVisibleSize|getVisibleOrigin)], SchedulerScriptHandlerEntry::[*], Size::[*], Point::[*], @@ -114,7 +116,7 @@ rename_functions = SpriteFrameCache::[addSpriteFramesWithFile=addSpriteFrames ge Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren], LabelAtlas::[create=_create], Sprite::[initWithFile=init], - SpriteBatchNode::[initWithFile=init], + SpriteBatchNode::[initWithFile=init removeAllChildrenWithCleanup=removeAllChildren], Touch::[getID=getId], SimpleAudioEngine::[preloadBackgroundMusic=preloadMusic setBackgroundMusicVolume=setMusicVolume getBackgroundMusicVolume=getMusicVolume playBackgroundMusic=playMusic stopBackgroundMusic=stopMusic pauseBackgroundMusic=pauseMusic resumeBackgroundMusic=resumeMusic rewindBackgroundMusic=rewindMusic isBackgroundMusicPlaying=isMusicPlaying willPlayBackgroundMusic=willPlayMusic], FileUtils::[loadFilenameLookupDictionaryFromFile=loadFilenameLookup] @@ -126,14 +128,14 @@ rename_classes = ParticleSystemQuad::ParticleSystem, remove_prefix = # classes for which there will be no "parent" lookup -classes_have_no_parents = Node Director SimpleAudioEngine FileUtils TMXMapInfo Application +classes_have_no_parents = Node Director SimpleAudioEngine FileUtils TMXMapInfo Application EGLViewProtocol # base classes which will be skipped when their sub-classes found them. base_classes_to_skip = Object Clonable # classes that create no constructor # Set is special and we will use a hand-written constructor -abstract_classes = Action FiniteTimeAction ActionInterval ActionEase EaseRateAction EaseElastic EaseBounce ActionInstant GridAction Grid3DAction TiledGrid3DAction Director SpriteFrameCache TransitionEaseScene Set SimpleAudioEngine FileUtils Application ClippingNode Label +abstract_classes = Action FiniteTimeAction ActionInterval ActionEase EaseRateAction EaseElastic EaseBounce ActionInstant GridAction Grid3DAction TiledGrid3DAction Director SpriteFrameCache TransitionEaseScene Set SimpleAudioEngine FileUtils Application ClippingNode Label EGLViewProtocol EGLView # Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'. script_control_cpp = no diff --git a/tools/tojs/cocos2dx_extension.ini b/tools/tojs/cocos2dx_extension.ini index 41ecc9e5a6..a5170a5d86 100644 --- a/tools/tojs/cocos2dx_extension.ini +++ b/tools/tojs/cocos2dx_extension.ini @@ -26,7 +26,7 @@ headers = %(cocosdir)s/extensions/cocos-ext.h # what classes to produce code for. You can use regular expressions here. When testing the regular # expression, it will be enclosed in "^$", like this: "^Menu*$". -classes = AssetsManager.* CCBReader.* CCBAnimationManager.* Scale9Sprite Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$ EditBox$ +classes = AssetsManager.* CCBReader.* CCBAnimationManager.* Scale9Sprite Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$ EditBox$ Armature ArmatureAnimation Skin Bone ArmatureDataManager # what should we skip? in the format ClassName::[function function] # ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also @@ -47,13 +47,15 @@ skip = CCBReader::[^CCBReader$ addOwnerCallbackName isJSControlled readByte getC AssetsManagerDelegateProtocol::[*], Control::[removeHandleOfControlEvent addHandleOfControlEvent], ControlUtils::[*], - ControlSwitchSprite::[*] + ControlSwitchSprite::[*], + Armature::[createBone updateBlendType getBody setBody getShapeList .*BlendFunc], + Skin::[getSkinData setSkinData], + ArmatureAnimation::[updateHandler updateFrameData frameEvent] -rename_functions = CCBReader::[getAnimationManager=getActionManager setAnimationManager=setActionManager], - CCBAnimationManager::[setCallFunc=setCallFuncForJSCallbackNamed] +rename_functions = rename_classes = CCBReader::_Reader, - CCBAnimationManager::AnimationManager + CCBAnimationManager::BuilderAnimationManager # for all class names, should we remove something when registering in the target VM? remove_prefix = @@ -62,11 +64,11 @@ remove_prefix = classes_have_no_parents = # base classes which will be skipped when their sub-classes found them. -base_classes_to_skip = Object +base_classes_to_skip = Object ProcessBase # classes that create no constructor # Set is special and we will use a hand-written constructor -abstract_classes = +abstract_classes = ArmatureDataManager # Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'. script_control_cpp = no From 98fc2e61d26dfebf9d246ec113229ed07649a5a8 Mon Sep 17 00:00:00 2001 From: rablwupei Date: Tue, 8 Oct 2013 19:50:24 +0800 Subject: [PATCH 017/116] add feature: cc.Sequence.create() and cc.Spawn.create() can pass Array actions. eg: cc.Sequence.create([cc.Show.create(), cc.Delay.create(1), cc.Hide.create()]); --- .../javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id index ec4aa352c7..9ff7a17801 100644 --- a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id +++ b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id @@ -1 +1 @@ -b88df18e2512b5111debda3991f51c2e72a2e5da \ No newline at end of file +db6aaa41d0756117258eebb759cd6420f66071e0 \ No newline at end of file From dee3065dbe8f64045718410db777bd94f75c25dc Mon Sep 17 00:00:00 2001 From: rablwupei Date: Tue, 8 Oct 2013 19:56:03 +0800 Subject: [PATCH 018/116] fix memory leak --- scripting/javascript/bindings/ScriptingCore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index 3a6f4aa4ae..33fd2aee1f 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -521,6 +521,7 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c &length); if (data) { script = JS_DecodeScript(cx, data, length, NULL, NULL); + CC_SAFE_DELETE_ARRAY(data); } // b) no jsc file, check js file From 5ea249a265e6d6f1ee88e94002bf721410a1245f Mon Sep 17 00:00:00 2001 From: rablwupei Date: Tue, 8 Oct 2013 20:03:10 +0800 Subject: [PATCH 019/116] fix memory leak --- extensions/spine/Atlas.cpp | 2 +- extensions/spine/SkeletonJson.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/spine/Atlas.cpp b/extensions/spine/Atlas.cpp index 281e214d77..8b9861463f 100644 --- a/extensions/spine/Atlas.cpp +++ b/extensions/spine/Atlas.cpp @@ -303,7 +303,7 @@ Atlas* Atlas_readAtlasFile (const char* path) { data = _Util_readFile(path, &length); if (data) atlas = Atlas_readAtlas(data, length, dir); - FREE(data); + delete [] data; FREE(dir); return atlas; } diff --git a/extensions/spine/SkeletonJson.cpp b/extensions/spine/SkeletonJson.cpp index 965a43f2a5..35a0daa787 100644 --- a/extensions/spine/SkeletonJson.cpp +++ b/extensions/spine/SkeletonJson.cpp @@ -240,7 +240,7 @@ SkeletonData* SkeletonJson_readSkeletonDataFile (SkeletonJson* self, const char* return 0; } skeletonData = SkeletonJson_readSkeletonData(self, json); - FREE(json); + delete [] json; return skeletonData; } From ce27a4eb141b6c950a4885e92e9406dc7a9cfa8b Mon Sep 17 00:00:00 2001 From: minggo Date: Wed, 9 Oct 2013 10:13:59 +0800 Subject: [PATCH 020/116] [ci skip] --- AUTHORS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index a87525d295..5d8360eadb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -615,6 +615,9 @@ Retired Core Developers: Project creator: use absolute path for json config files Documentation fixes A better way to locate project creator + + rablwupei + Fixed a memory leak in ScriptingCore::runScript() Cocos2d-x can not grow so fast without the active community. From 938db14bc3ae58cb5ed0157ab2517d9687bd2511 Mon Sep 17 00:00:00 2001 From: CocosRobot Date: Wed, 9 Oct 2013 02:14:04 +0000 Subject: [PATCH 021/116] [AUTO] : updating submodule reference to latest autogenerated bindings --- scripting/auto-generated | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/auto-generated b/scripting/auto-generated index 946a5276fb..62651f8934 160000 --- a/scripting/auto-generated +++ b/scripting/auto-generated @@ -1 +1 @@ -Subproject commit 946a5276fb9b072ee9ceeb8f49c1aeeea66ab9c4 +Subproject commit 62651f8934ba0225136b11d0c23bfd09c3aa2414 From 3548d46b380dd776f9e479cb6e4c7e2bcb03511f Mon Sep 17 00:00:00 2001 From: minggo Date: Wed, 9 Oct 2013 10:17:17 +0800 Subject: [PATCH 022/116] [ci skip] --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index febeb69cfa..b0f55118b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ cocos2d-x-3.0alpha1 @??? 2013 [NEW] Added Cocos2dxHelper.runOnGLThread(Runnable) again [Mac] [FIX] Removed unused CCLOG() from GL initialization +[Javascript binding] + [FIX] Fixed a memory leak in ScriptingCore::runScript() cocos2d-x-3.0alpha0 @Sep.19 2013 [all platforms] From 179eef9d8c617aa53e75352e54f3061a23bd4261 Mon Sep 17 00:00:00 2001 From: minggo Date: Wed, 9 Oct 2013 11:25:45 +0800 Subject: [PATCH 023/116] [ci skip] --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 5d8360eadb..47e07250c2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -618,6 +618,7 @@ Retired Core Developers: rablwupei Fixed a memory leak in ScriptingCore::runScript() + Fixed a memory leak in Spine Cocos2d-x can not grow so fast without the active community. From cd9689da1a1bae137abe7fd0393168e5cb3fd09a Mon Sep 17 00:00:00 2001 From: minggo Date: Wed, 9 Oct 2013 11:27:12 +0800 Subject: [PATCH 024/116] [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b0f55118b9..40fcdf73f6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ cocos2d-x-3.0alpha1 @??? 2013 [all platforms] [DOC] Added RELEASE_NOTES and CODING_STYLE.md files [FIX] Texture: use CCLOG to log when a texture is being decoded in software + [FIX] Spine: fix memory leaks [Android] [FIX] Added EGL_RENDERABLE_TYPE to OpenGL attributes [NEW] Added Cocos2dxHelper.runOnGLThread(Runnable) again From 4747e37acf176ac56901e2a8c3e2edfecd4bf1c2 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Wed, 9 Oct 2013 13:41:19 +0800 Subject: [PATCH 025/116] issue #2771: let PhysicsShape::create doesn't need to pass the PhysicsBody --- cocos2dx/physics/CCPhysicsBody.cpp | 58 +++++--- cocos2dx/physics/CCPhysicsSetting.h | 5 + cocos2dx/physics/CCPhysicsShape.cpp | 133 ++++++++++-------- cocos2dx/physics/CCPhysicsShape.h | 38 ++--- cocos2dx/physics/CCPhysicsWorld.cpp | 2 + .../physics/chipmunk/CCPhysicsShapeInfo.cpp | 7 + .../physics/chipmunk/CCPhysicsShapeInfo.h | 4 +- .../Classes/PhysicsTest/PhysicsTest.cpp | 16 ++- 8 files changed, 162 insertions(+), 101 deletions(-) diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index b8a961a302..44acb0c11f 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -42,6 +42,8 @@ #include "Box2D/CCPhysicsJointInfo.h" #include "chipmunk/CCPhysicsWorldInfo.h" #include "Box2D/CCPhysicsWorldInfo.h" +#include "chipmunk/CCPhysicsShapeInfo.h" +#include "Box2D/CCPhysicsShapeInfo.h" #include "chipmunk/CCPhysicsHelper.h" #include "Box2D/CCPhysicsHelper.h" @@ -95,7 +97,7 @@ PhysicsBody* PhysicsBody::createCircle(float radius, float density) PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeCircle::create(body, radius, density)); + body->addShape(PhysicsShapeCircle::create(radius, density)); body->autorelease(); return body; } @@ -109,7 +111,7 @@ PhysicsBody* PhysicsBody::createBox(Size size, float density) PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeBox::create(body, size, density)); + body->addShape(PhysicsShapeBox::create(size, density)); body->autorelease(); return body; } @@ -123,7 +125,7 @@ PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, float density) PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapePolygon::create(body, points, count, density)); + body->addShape(PhysicsShapePolygon::create(points, count, density)); body->autorelease(); return body; } @@ -137,7 +139,7 @@ PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1 PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeSegment::create(body, a, b, border)); + body->addShape(PhysicsShapeEdgeSegment::create(a, b, border)); body->_dynamic = false; body->autorelease(); return body; @@ -152,7 +154,7 @@ PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeBox::create(body, size, border)); + body->addShape(PhysicsShapeEdgeBox::create(size, border)); body->_dynamic = false; body->autorelease(); return body; @@ -168,7 +170,7 @@ PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float bord PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapePolygon::create(body, points, count, border)); + body->addShape(PhysicsShapePolygon::create(points, count, border)); body->_dynamic = false; body->autorelease(); return body; @@ -184,7 +186,7 @@ PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeChain::create(body, points, count, border)); + body->addShape(PhysicsShapeEdgeChain::create(points, count, border)); body->_dynamic = false; body->autorelease(); return body; @@ -221,8 +223,8 @@ void PhysicsBody::setDynamic(bool dynamic) cpBodySetMoment(_info->body, PhysicsHelper::float2cpfloat(_angularDamping)); }else { - cpBodySetMass(_info->body, INFINITY); - cpBodySetMoment(_info->body, INFINITY); + cpBodySetMass(_info->body, PHYSICS_INFINITY); + cpBodySetMoment(_info->body, PHYSICS_INFINITY); } _dynamic = dynamic; @@ -254,18 +256,37 @@ void PhysicsBody::addShape(PhysicsShape* shape) { if (shape == nullptr) return; - if (shape->getBody() != this) CCASSERT(false, ""); + // already added + if (shape->getBody() == this) + { + return; + } + else if (shape->getBody() != nullptr) + { + shape->getBody()->removeShape(shape); + } + // reset the body + if (shape->_info->body != _info->body) + { + for (cpShape* subShape : shape->_info->shapes) + { + cpShapeSetBody(subShape, _info->body); + } + shape->_info->body = _info->body; + } + + // add shape to body if (std::find(_shapes.begin(), _shapes.end(), shape) == _shapes.end()) { + shape->setBody(this); _shapes.push_back(shape); - shape->_isAddToBody = true; // calculate the mass, area and desity _area += shape->getArea(); - if (_mass == INFINITY || shape->getMass() == INFINITY) + if (_mass == PHYSICS_INFINITY || shape->getMass() == PHYSICS_INFINITY) { - _mass = INFINITY; + _mass = PHYSICS_INFINITY; _massDefault = false; }else { @@ -279,9 +300,9 @@ void PhysicsBody::addShape(PhysicsShape* shape) if (!_massDefault) { - if (_mass == INFINITY) + if (_mass == PHYSICS_INFINITY) { - _density = INFINITY; + _density = PHYSICS_INFINITY; }else { _density = _mass / _area; @@ -389,11 +410,10 @@ void PhysicsBody::removeShape(PhysicsShape* shape) } _shapes.erase(it); - shape->_isAddToBody = false; // deduce the mass, area and angularDamping - if (_mass != INFINITY && shape->getMass() != INFINITY) + if (_mass != PHYSICS_INFINITY && shape->getMass() != PHYSICS_INFINITY) { if (_mass - shape->getMass() <= 0) { @@ -406,9 +426,9 @@ void PhysicsBody::removeShape(PhysicsShape* shape) _area -= shape->getArea(); - if (_mass == INFINITY) + if (_mass == PHYSICS_INFINITY) { - _density = INFINITY; + _density = PHYSICS_INFINITY; } else if (_area > 0) { diff --git a/cocos2dx/physics/CCPhysicsSetting.h b/cocos2dx/physics/CCPhysicsSetting.h index 98b39f8f66..b29b12054d 100644 --- a/cocos2dx/physics/CCPhysicsSetting.h +++ b/cocos2dx/physics/CCPhysicsSetting.h @@ -43,4 +43,9 @@ #define CC_USE_PHYSICS #endif +namespace cocos2d +{ + extern const float PHYSICS_INFINITY; +} + #endif // __CCPHYSICS_SETTING_H__ diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index 35edfb5f1e..0b80d9ae68 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -52,7 +52,6 @@ PhysicsShape::PhysicsShape() , _density(0) , _tag(0) , _enable(true) -, _isAddToBody(false) { } @@ -62,12 +61,8 @@ PhysicsShape::~PhysicsShape() CC_SAFE_DELETE(_info); } -bool PhysicsShape::init(PhysicsBody* body, Type type) +bool PhysicsShape::init(Type type) { - if (body == nullptr) return false; - - _body = body; - _info = new PhysicsShapeInfo(this); if (_info == nullptr) return false; @@ -107,7 +102,13 @@ void PhysicsShape::addToBody() PhysicsBodyInfo* PhysicsShape::bodyInfo() const { - return _body->_info; + if (_body != nullptr) + { + return _body->_info; + }else + { + return nullptr; + } } PhysicsShapeCircle::PhysicsShapeCircle() @@ -182,11 +183,28 @@ PhysicsShapeEdgeSegment::~PhysicsShapeEdgeSegment() #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) + +void PhysicsShape::setElasticity(float elasticity) +{ + for (cpShape* shape : _info->shapes) + { + cpShapeSetElasticity(shape, PhysicsHelper::float2cpfloat(elasticity)); + } +} + +void PhysicsShape::setFriction(float friction) +{ + for (cpShape* shape : _info->shapes) + { + cpShapeSetFriction(shape, PhysicsHelper::float2cpfloat(friction)); + } +} + // PhysicsShapeCircle -PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeCircle* shape = new PhysicsShapeCircle(); - if (shape && shape->init(body, radius, density, offset)) + if (shape && shape->init(radius, density, offset)) { shape->autorelease(); return shape; @@ -196,20 +214,20 @@ PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, return nullptr; } -bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeCircle::init(float radius, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::CIRCLE)); + CC_BREAK_IF(!PhysicsShape::init(Type::CIRCLE)); - cpShape* shape = cpCircleShapeNew(bodyInfo()->body, radius, PhysicsHelper::point2cpv(offset)); + cpShape* shape = cpCircleShapeNew(_info->shareBody, radius, PhysicsHelper::point2cpv(offset)); CC_BREAK_IF(shape == nullptr); _density = density; _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); - _mass = _density == INFINITY ? INFINITY : _density * _area; - _angularDamping = _mass == INFINITY ? INFINITY : cpMomentForCircle(_mass, 0, radius, PhysicsHelper::point2cpv(offset)); + _mass = _density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForCircle(_mass, 0, radius, PhysicsHelper::point2cpv(offset)); _info->add(shape); @@ -220,10 +238,10 @@ bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, float density/* = } // PhysicsShapeEdgeSegment -PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(PhysicsBody* body, Point a, Point b, float border/* = 1*/) +PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(Point a, Point b, float border/* = 1*/) { PhysicsShapeEdgeSegment* shape = new PhysicsShapeEdgeSegment(); - if (shape && shape->init(body, a, b, border)) + if (shape && shape->init(a, b, border)) { shape->autorelease(); return shape; @@ -233,21 +251,21 @@ PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(PhysicsBody* body, Poin return nullptr; } -bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float border/* = 1*/) +bool PhysicsShapeEdgeSegment::init(Point a, Point b, float border/* = 1*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGESEGMENT)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGESEGMENT)); - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, + cpShape* shape = cpSegmentShapeNew(_info->shareBody, PhysicsHelper::point2cpv(a), PhysicsHelper::point2cpv(b), PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); - _density = INFINITY; - _angularDamping = INFINITY; + _density = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; _info->add(shape); @@ -258,10 +276,10 @@ bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float bo } // PhysicsShapeBox -PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeBox* PhysicsShapeBox::create(Size size, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeBox* shape = new PhysicsShapeBox(); - if (shape && shape->init(body, size, density, offset)) + if (shape && shape->init(size, density, offset)) { shape->autorelease(); return shape; @@ -271,13 +289,13 @@ PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, float den return nullptr; } -bool PhysicsShapeBox::init(PhysicsBody* body, Size size, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeBox::init(Size size, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::BOX)); + CC_BREAK_IF(!PhysicsShape::init(Type::BOX)); - cpShape* shape = cpBoxShapeNew(bodyInfo()->body, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); + cpShape* shape = cpBoxShapeNew(_info->shareBody, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); CC_BREAK_IF(shape == nullptr); @@ -298,10 +316,10 @@ bool PhysicsShapeBox::init(PhysicsBody* body, Size size, float density/* = 0*/, } // PhysicsShapeCircle -PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* points, int count, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapePolygon* PhysicsShapePolygon::create(Point* points, int count, float density/* = 0*/, Point offset/* = Point(0, 0)*/) { PhysicsShapePolygon* shape = new PhysicsShapePolygon(); - if (shape && shape->init(body, points, count, density, offset)) + if (shape && shape->init(points, count, density, offset)) { shape->autorelease(); return shape; @@ -311,15 +329,15 @@ PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* point return nullptr; } -bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapePolygon::init(Point* points, int count, float density/* = 0*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::POLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::POLYGEN)); cpVect* vecs = new cpVect[count]; PhysicsHelper::points2cpvs(points, vecs, count); - cpShape* shape = cpPolyShapeNew(bodyInfo()->body, count, vecs, PhysicsHelper::point2cpv(offset)); + cpShape* shape = cpPolyShapeNew(_info->shareBody, count, vecs, PhysicsHelper::point2cpv(offset)); CC_SAFE_DELETE(vecs); CC_BREAK_IF(shape == nullptr); @@ -341,10 +359,10 @@ bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, floa } // PhysicsShapeEdgeBox -PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(PhysicsBody* body, Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeEdgeBox* shape = new PhysicsShapeEdgeBox(); - if (shape && shape->init(body, size, border, offset)) + if (shape && shape->init(size, border, offset)) { shape->autorelease(); return shape; @@ -354,24 +372,22 @@ PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(PhysicsBody* body, Size size, f return nullptr; } -bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1*/, Point offset/*= Point(0, 0)*/) +bool PhysicsShapeEdgeBox::init(Size size, float border/* = 1*/, Point offset/*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGEBOX)); - - Point bodyPos = body->getPosition(); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEBOX)); cpVect vec[4] = {}; - vec[0] = PhysicsHelper::point2cpv(Point(bodyPos.x-size.width/2+offset.x, bodyPos.y-size.height/2+offset.y)); - vec[1] = PhysicsHelper::point2cpv(Point(bodyPos.x+size.width/2+offset.x, bodyPos.y-size.height/2+offset.y)); - vec[2] = PhysicsHelper::point2cpv(Point(bodyPos.x+size.width/2+offset.x, bodyPos.y+size.height/2+offset.y)); - vec[3] = PhysicsHelper::point2cpv(Point(bodyPos.x-size.width/2+offset.x, bodyPos.y+size.height/2+offset.y)); + vec[0] = PhysicsHelper::point2cpv(Point(-size.width/2+offset.x, -size.height/2+offset.y)); + vec[1] = PhysicsHelper::point2cpv(Point(+size.width/2+offset.x, -size.height/2+offset.y)); + vec[2] = PhysicsHelper::point2cpv(Point(+size.width/2+offset.x, +size.height/2+offset.y)); + vec[3] = PhysicsHelper::point2cpv(Point(-size.width/2+offset.x, +size.height/2+offset.y)); int i = 0; for (; i < 4; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[(i+1)%4], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[(i+1)%4], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); cpShapeSetElasticity(shape, 1.0f); @@ -380,8 +396,8 @@ bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1* } CC_BREAK_IF(i < 4); - _mass = INFINITY; - _angularDamping = INFINITY; + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; return true; } while (false); @@ -390,10 +406,10 @@ bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1* } // PhysicsShapeEdgeBox -PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(Point* points, int count, float border/* = 1*/) { PhysicsShapeEdgePolygon* shape = new PhysicsShapeEdgePolygon(); - if (shape && shape->init(body, points, count, border)) + if (shape && shape->init(points, count, border)) { shape->autorelease(); return shape; @@ -403,12 +419,12 @@ PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(PhysicsBody* body, Poin return nullptr; } -bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgePolygon::init(Point* points, int count, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGEPOLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEPOLYGEN)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -416,7 +432,7 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, int i = 0; for (; i < count; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[(i+1)%count], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[(i+1)%count], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); cpShapeSetElasticity(shape, 1.0f); @@ -427,8 +443,8 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, CC_BREAK_IF(i < count); - _mass = INFINITY; - _angularDamping = INFINITY; + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; return true; } while (false); @@ -439,10 +455,10 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, } // PhysicsShapeEdgeChain -PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(Point* points, int count, float border/* = 1*/) { PhysicsShapeEdgeChain* shape = new PhysicsShapeEdgeChain(); - if (shape && shape->init(body, points, count, border)) + if (shape && shape->init(points, count, border)) { shape->autorelease(); return shape; @@ -452,12 +468,12 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(PhysicsBody* body, Point* p return nullptr; } -bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgeChain::init(Point* points, int count, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGECHAIN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGECHAIN)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -465,7 +481,7 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl int i = 0; for (; i < count - 1; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[i+1], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[i+1], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); cpShapeSetElasticity(shape, 1.0f); @@ -475,8 +491,8 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl if (vec != nullptr) delete[] vec; CC_BREAK_IF(i < count); - _mass = INFINITY; - _angularDamping = INFINITY; + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; return true; } while (false); @@ -486,7 +502,6 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl return false; } - #elif (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) #endif diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index 3d431f96e7..aea4a9e36d 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -71,14 +71,21 @@ public: inline bool isEnable() { return _enable; } void addToBody(); + void setElasticity(float elasticity); + void setFriction(float friction); + + + protected: - bool init(PhysicsBody* body, Type type); + bool init(Type type); /** * @brief PhysicsShape is PhysicsBody's friend class, but all the subclasses isn't. so this method is use for subclasses to catch the bodyInfo from PhysicsBody. */ PhysicsBodyInfo* bodyInfo() const; + inline void setBody(PhysicsBody* body) { _body = body; } + protected: PhysicsShape(); virtual ~PhysicsShape() = 0; @@ -93,7 +100,6 @@ protected: float _density; int _tag; bool _enable; - bool _isAddToBody; friend class PhysicsWorld; friend class PhysicsBody; @@ -103,10 +109,10 @@ protected: class PhysicsShapeCircle : public PhysicsShape { public: - static PhysicsShapeCircle* create(PhysicsBody* body, float radius, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapeCircle* create(float radius, float density = 0, Point offset = Point(0, 0)); protected: - bool init(PhysicsBody* body, float radius, float density = 0, Point offset = Point(0, 0)); + bool init(float radius, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapeCircle(); @@ -119,10 +125,10 @@ protected: class PhysicsShapeBox : public PhysicsShape { public: - static PhysicsShapeBox* create(PhysicsBody* body, Size size, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapeBox* create(Size size, float density = 0, Point offset = Point(0, 0)); protected: - bool init(PhysicsBody* body, Size size, float density = 0, Point offset = Point(0, 0)); + bool init(Size size, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapeBox(); @@ -135,10 +141,10 @@ protected: class PhysicsShapePolygon : public PhysicsShape { public: - static PhysicsShapePolygon* create(PhysicsBody* body, Point* points, int count, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapePolygon* create(Point* points, int count, float density = 0, Point offset = Point(0, 0)); protected: - bool init(PhysicsBody* body, Point* points, int count, float density = 0, Point offset = Point(0, 0)); + bool init(Point* points, int count, float density = 0, Point offset = Point(0, 0)); protected: PhysicsShapePolygon(); @@ -151,10 +157,10 @@ protected: class PhysicsShapeEdgeSegment : public PhysicsShape { public: - static PhysicsShapeEdgeSegment* create(PhysicsBody* body, Point a, Point b, float border = 1); + static PhysicsShapeEdgeSegment* create(Point a, Point b, float border = 1); protected: - bool init(PhysicsBody* body, Point a, Point b, float border = 1); + bool init(Point a, Point b, float border = 1); protected: PhysicsShapeEdgeSegment(); @@ -167,10 +173,10 @@ protected: class PhysicsShapeEdgeBox : public PhysicsShape { public: - static PhysicsShapeEdgeBox* create(PhysicsBody* body, Size size, float border = 0, Point offset = Point(0, 0)); + static PhysicsShapeEdgeBox* create(Size size, float border = 0, Point offset = Point(0, 0)); protected: - bool init(PhysicsBody* body, Size size, float border = 1, Point offset = Point(0, 0)); + bool init(Size size, float border = 1, Point offset = Point(0, 0)); protected: PhysicsShapeEdgeBox(); @@ -183,10 +189,10 @@ protected: class PhysicsShapeEdgePolygon : public PhysicsShape { public: - static PhysicsShapeEdgePolygon* create(PhysicsBody* body, Point* points, int count, float border = 1); + static PhysicsShapeEdgePolygon* create(Point* points, int count, float border = 1); protected: - bool init(PhysicsBody* body, Point* points, int count, float border = 1); + bool init(Point* points, int count, float border = 1); protected: PhysicsShapeEdgePolygon(); @@ -199,10 +205,10 @@ protected: class PhysicsShapeEdgeChain : public PhysicsShape { public: - static PhysicsShapeEdgeChain* create(PhysicsBody* body, Point* points, int count, float border = 1); + static PhysicsShapeEdgeChain* create(Point* points, int count, float border = 1); protected: - bool init(PhysicsBody* body, Point* points, int count, float border = 1); + bool init(Point* points, int count, float border = 1); protected: PhysicsShapeEdgeChain(); diff --git a/cocos2dx/physics/CCPhysicsWorld.cpp b/cocos2dx/physics/CCPhysicsWorld.cpp index 580fd5fe75..6f0fa1295c 100644 --- a/cocos2dx/physics/CCPhysicsWorld.cpp +++ b/cocos2dx/physics/CCPhysicsWorld.cpp @@ -57,6 +57,8 @@ NS_CC_BEGIN #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +const float PHYSICS_INFINITY = INFINITY; + int PhysicsWorld::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, void *data) { PhysicsWorld* world = static_cast(data); diff --git a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp index 0e660792ad..0c048c780b 100644 --- a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp +++ b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp @@ -28,10 +28,17 @@ NS_CC_BEGIN std::map PhysicsShapeInfo::map; +cpBody* PhysicsShapeInfo::shareBody = nullptr; PhysicsShapeInfo::PhysicsShapeInfo(PhysicsShape* shape) : shape(shape) { + if (shareBody == nullptr) + { + shareBody = cpBodyNewStatic(); + } + + body = shareBody; } PhysicsShapeInfo::~PhysicsShapeInfo() diff --git a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h index 7e0be63747..5e9f2a73e3 100644 --- a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h +++ b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h @@ -46,8 +46,10 @@ public: public: std::vector shapes; - static std::map map; PhysicsShape* shape; + cpBody* body; + static std::map map; + static cpBody* shareBody; private: PhysicsShapeInfo(PhysicsShape* shape); diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index ebab929dec..3135e2481a 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -51,11 +51,7 @@ namespace bool PhysicsTestScene::initTest() { #ifdef CC_USE_PHYSICS - if (TestScene::initWithPhysics()) - { - this->getPhysicsWorld()->setDebugDraw(true); - return true; - } + return TestScene::initWithPhysics(); #else return TestScene::init(); #endif @@ -297,6 +293,12 @@ Node* PhysicsDemoLogoSmash::makeBall(float x, float y) ball->setScale(0.1); PhysicsBody* body = PhysicsBody::createCircle(0.95); + body->setMass(1.0); + body->setAngularDamping(PHYSICS_INFINITY); + + body->getShape()->setElasticity(0); + body->getShape()->setFriction(0); + //body->setDynamic(false); ball->setPhysicsBody(body); @@ -331,8 +333,10 @@ void PhysicsDemoLogoSmash::onEnter() Sprite* bullet = Sprite::create("Images/ball.png"); bullet->setScale(0.5); - PhysicsBody* body = PhysicsBody::createCircle(3, INFINITY); + PhysicsBody* body = PhysicsBody::createCircle(8, PHYSICS_INFINITY); body->setVelocity(Point(400, 0)); + body->getShape()->setElasticity(0); + body->getShape()->setFriction(0); bullet->setPhysicsBody(body); bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2)); From 5b05731daf678c8349695575acc727a32ec69fd4 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 9 Oct 2013 14:23:36 +0800 Subject: [PATCH 026/116] Update AUTHORS. --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 47e07250c2..2c056b6364 100644 --- a/AUTHORS +++ b/AUTHORS @@ -618,7 +618,8 @@ Retired Core Developers: rablwupei Fixed a memory leak in ScriptingCore::runScript() - Fixed a memory leak in Spine + Fixed a memory leak in Spine. + Added support of passing array to cc.Sequence.create and cc.Spawn.create. Cocos2d-x can not grow so fast without the active community. From ac16283d8a85ba9a0a91002c8acaf794e768535e Mon Sep 17 00:00:00 2001 From: CocosRobot Date: Wed, 9 Oct 2013 06:28:04 +0000 Subject: [PATCH 027/116] [AUTO] : updating submodule reference to latest autogenerated bindings --- scripting/auto-generated | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/auto-generated b/scripting/auto-generated index 62651f8934..ec90d1c35d 160000 --- a/scripting/auto-generated +++ b/scripting/auto-generated @@ -1 +1 @@ -Subproject commit 62651f8934ba0225136b11d0c23bfd09c3aa2414 +Subproject commit ec90d1c35d06c1de3cb5079f885c22c45b8f129b From 476c5647be1997efaaaaa86ac2a8a657b53911bc Mon Sep 17 00:00:00 2001 From: zhangbin Date: Wed, 9 Oct 2013 15:55:04 +0800 Subject: [PATCH 028/116] closed #2909, Solve the Chinese string from C++ to JS is messy code in plugin. --- plugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin b/plugin index d583b83c58..915a29d230 160000 --- a/plugin +++ b/plugin @@ -1 +1 @@ -Subproject commit d583b83c5806a0d44788095dfc541fb2812c600e +Subproject commit 915a29d230b785bdea4bce39e643ce7ce667f6d0 From d51a04585cf6cd2b65d8e3397704cc51120aa440 Mon Sep 17 00:00:00 2001 From: rablwupei Date: Wed, 9 Oct 2013 16:48:05 +0800 Subject: [PATCH 029/116] fix bug: sys.localStorage.getItem() do not support utf8 in jsb. --- scripting/javascript/bindings/js_bindings_system_functions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripting/javascript/bindings/js_bindings_system_functions.cpp b/scripting/javascript/bindings/js_bindings_system_functions.cpp index 9960f42b2c..1cb171224b 100644 --- a/scripting/javascript/bindings/js_bindings_system_functions.cpp +++ b/scripting/javascript/bindings/js_bindings_system_functions.cpp @@ -14,6 +14,7 @@ #include "js_bindings_core.h" #include "js_manual_conversions.h" #include "js_bindings_system_functions.h" +#include "ScriptingCore.h" USING_NS_CC; @@ -31,7 +32,7 @@ JSBool JSB_localStorageGetItem(JSContext *cx, uint32_t argc, jsval *vp) { ret_val = localStorageGetItem((char*)arg0 ); - jsval ret_jsval = charptr_to_jsval( cx, ret_val); + jsval ret_jsval = c_string_to_jsval(cx, ret_val ? ret_val : ""); JS_SET_RVAL(cx, vp, ret_jsval ); return JS_TRUE; From a4053c805ff006bd9c4d60368b270727e8074e1a Mon Sep 17 00:00:00 2001 From: rablwupei Date: Wed, 9 Oct 2013 16:51:37 +0800 Subject: [PATCH 030/116] fix XMLHTTPRequest.cpp memory leak --- scripting/javascript/bindings/XMLHTTPRequest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripting/javascript/bindings/XMLHTTPRequest.cpp b/scripting/javascript/bindings/XMLHTTPRequest.cpp index e334833fa3..b799f6aacf 100644 --- a/scripting/javascript/bindings/XMLHTTPRequest.cpp +++ b/scripting/javascript/bindings/XMLHTTPRequest.cpp @@ -99,6 +99,8 @@ void MinXmlHttpRequest::_gotHeader(string header) pch = strtok (NULL, " "); } } + + CC_SAFE_DELETE_ARRAY(cstr); } /** From e03dd0714e63e3a920805e682d8306928554180d Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 9 Oct 2013 16:59:36 +0800 Subject: [PATCH 031/116] Update CHANGELOG [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 40fcdf73f6..9bc3581f84 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ cocos2d-x-3.0alpha1 @??? 2013 [FIX] Removed unused CCLOG() from GL initialization [Javascript binding] [FIX] Fixed a memory leak in ScriptingCore::runScript() + [FIX] sys.localStorage.getItem() does not support non-ascii string. cocos2d-x-3.0alpha0 @Sep.19 2013 [all platforms] From 23d1b4c3c254bb878cf3651917ef0cb019a6126f Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 9 Oct 2013 17:00:46 +0800 Subject: [PATCH 032/116] Update AUTHORS [ci skip] --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 2c056b6364..dfec343959 100644 --- a/AUTHORS +++ b/AUTHORS @@ -620,6 +620,7 @@ Retired Core Developers: Fixed a memory leak in ScriptingCore::runScript() Fixed a memory leak in Spine. Added support of passing array to cc.Sequence.create and cc.Spawn.create. + Fixed a bug that sys.localStorage.getItem() does not support non-ascii string. Cocos2d-x can not grow so fast without the active community. From 6551ef2c169a7f6b63c56b63c8ee18cdebfeccff Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 9 Oct 2013 17:04:43 +0800 Subject: [PATCH 033/116] Update AUTHORS [ci skip] --- AUTHORS | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/AUTHORS b/AUTHORS index dfec343959..c4df157fd3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -587,18 +587,6 @@ Developers: signmotion (Andrey Syrokomsky) Fixed some compiling-warnings (MSVC2012). -Retired Core Developers: - WenSheng Yang - Author of windows port, CCTextField, - Designer of CCApplication/CCEGLView/platform structure. - He's working together with 2dx core team but leading FishingJoy game - - Bin Zhang - core-team member but put himself in FishingJoy game since 2012. - - RongHong Huang (flyingpaper) - Author of cocos2d-xna and spent all his time on wp7. - michaelcontento [Android] use onWindowFocusChanged(bool) instead of onResume()/onPause() Prevent nullptr access in AssetsManager @@ -621,6 +609,20 @@ Retired Core Developers: Fixed a memory leak in Spine. Added support of passing array to cc.Sequence.create and cc.Spawn.create. Fixed a bug that sys.localStorage.getItem() does not support non-ascii string. + Fixed a memory leak in XMLHttpRequest. + +Retired Core Developers: + WenSheng Yang + Author of windows port, CCTextField, + Designer of CCApplication/CCEGLView/platform structure. + He's working together with 2dx core team but leading FishingJoy game + + Bin Zhang + core-team member but put himself in FishingJoy game since 2012. + + RongHong Huang (flyingpaper) + Author of cocos2d-xna and spent all his time on wp7. + Cocos2d-x can not grow so fast without the active community. From e3b30b221b91355273909ef3239499cfd2497466 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 9 Oct 2013 17:06:55 +0800 Subject: [PATCH 034/116] Update CHNAGELOG [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 9bc3581f84..81416cfc94 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ cocos2d-x-3.0alpha1 @??? 2013 [DOC] Added RELEASE_NOTES and CODING_STYLE.md files [FIX] Texture: use CCLOG to log when a texture is being decoded in software [FIX] Spine: fix memory leaks + [FIX] fixed a memory leak in XMLHTTPRequest.cpp [Android] [FIX] Added EGL_RENDERABLE_TYPE to OpenGL attributes [NEW] Added Cocos2dxHelper.runOnGLThread(Runnable) again From 381f904cd4e96ce2a74ecc799ae01e7fb2203e52 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Wed, 9 Oct 2013 17:53:12 +0800 Subject: [PATCH 035/116] issue #2771: add PhysicsMaterial --- .../CCScene.cpp | 1 + cocos2dx/physics/CCPhysicsBody.cpp | 43 +++-- cocos2dx/physics/CCPhysicsBody.h | 22 ++- cocos2dx/physics/CCPhysicsShape.cpp | 104 +++++++----- cocos2dx/physics/CCPhysicsShape.h | 65 ++++--- cocos2dx/physics/CCPhysicsWorld.cpp | 2 - .../Classes/PhysicsTest/PhysicsTest.cpp | 160 +++++++++++------- .../TestCpp/Classes/PhysicsTest/PhysicsTest.h | 34 +++- 8 files changed, 268 insertions(+), 163 deletions(-) diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp index 50b67e50e0..9081c5c630 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp +++ b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp @@ -43,6 +43,7 @@ Scene::Scene() Scene::~Scene() { + CC_SAFE_DELETE(_physicsWorld); } bool Scene::init() diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index 44acb0c11f..4c2c1c65d7 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -92,12 +92,12 @@ PhysicsBody::~PhysicsBody() } } -PhysicsBody* PhysicsBody::createCircle(float radius, float density) +PhysicsBody* PhysicsBody::createCircle(float radius, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeCircle::create(radius, density)); + body->addShape(PhysicsShapeCircle::create(radius, material)); body->autorelease(); return body; } @@ -106,12 +106,12 @@ PhysicsBody* PhysicsBody::createCircle(float radius, float density) return nullptr; } -PhysicsBody* PhysicsBody::createBox(Size size, float density) +PhysicsBody* PhysicsBody::createBox(Size size, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeBox::create(size, density)); + body->addShape(PhysicsShapeBox::create(size, material)); body->autorelease(); return body; } @@ -120,12 +120,12 @@ PhysicsBody* PhysicsBody::createBox(Size size, float density) return nullptr; } -PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, float density) +PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapePolygon::create(points, count, density)); + body->addShape(PhysicsShapePolygon::create(points, count, material)); body->autorelease(); return body; } @@ -134,12 +134,12 @@ PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, float density) return nullptr; } -PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeSegment::create(a, b, border)); + body->addShape(PhysicsShapeEdgeSegment::create(a, b, material, border)); body->_dynamic = false; body->autorelease(); return body; @@ -149,12 +149,12 @@ PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1 return nullptr; } -PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgeBox(Size size, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeBox::create(size, border)); + body->addShape(PhysicsShapeEdgeBox::create(size, material, border)); body->_dynamic = false; body->autorelease(); return body; @@ -165,12 +165,12 @@ PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) return nullptr; } -PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapePolygon::create(points, count, border)); + body->addShape(PhysicsShapeEdgePolygon::create(points, count, material, border)); body->_dynamic = false; body->autorelease(); return body; @@ -181,12 +181,12 @@ PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float bord return nullptr; } -PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addShape(PhysicsShapeEdgeChain::create(points, count, border)); + body->addShape(PhysicsShapeEdgeChain::create(points, count, material, border)); body->_dynamic = false; body->autorelease(); return body; @@ -311,9 +311,18 @@ void PhysicsBody::addShape(PhysicsShape* shape) if (shape->getAngularDumping() > 0) { - _angularDamping = (_angularDampingDefault ? 0 : _angularDamping) + shape->getAngularDumping(); - _angularDampingDefault = false; - cpBodySetMoment(_info->body, _angularDamping); + if (shape->getAngularDumping() == INFINITY) + { + _angularDamping = INFINITY; + _angularDampingDefault = false; + cpBodySetMoment(_info->body, _angularDamping); + } + else if (_angularDamping != INFINITY) + { + _angularDamping = (_angularDampingDefault ? 0 : _angularDamping) + shape->getAngularDumping(); + _angularDampingDefault = false; + cpBodySetMoment(_info->body, _angularDamping); + } } if (_world != nullptr) _world->addShape(shape); diff --git a/cocos2dx/physics/CCPhysicsBody.h b/cocos2dx/physics/CCPhysicsBody.h index 580bec840d..505235de0a 100644 --- a/cocos2dx/physics/CCPhysicsBody.h +++ b/cocos2dx/physics/CCPhysicsBody.h @@ -30,15 +30,21 @@ #include "cocoa/CCObject.h" #include "cocoa/CCGeometry.h" + +#include "CCPhysicsShape.h" + #include NS_CC_BEGIN class Sprite; class PhysicsWorld; class PhysicsJoint; -class PhysicsShape; class PhysicsBodyInfo; + + +const PhysicsMaterial PHYSICSBODY_MATERIAL_DEFAULT = {0.0f, 1.0f, 1.0f}; + /** * A body affect by physics. * it can attach one or more shapes. @@ -49,33 +55,33 @@ public: /** * @brief Create a body contains a circle shape. */ - static PhysicsBody* createCircle(float radius, float density = 1); + static PhysicsBody* createCircle(float radius, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a box shape. */ - static PhysicsBody* createBox(Size size, float density = 1); + static PhysicsBody* createBox(Size size, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a polygon shape. * points is an array of Point structs defining a convex hull with a clockwise winding. */ - static PhysicsBody* createPolygon(Point* points, int count, float density = 1); + static PhysicsBody* createPolygon(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a EdgeSegment shape. */ - static PhysicsBody* createEdgeSegment(Point a, Point b, float border = 1); + static PhysicsBody* createEdgeSegment(Point a, Point b, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgeBox shape. */ - static PhysicsBody* createEdgeBox(Size size, float border = 1); + static PhysicsBody* createEdgeBox(Size size, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgePolygon shape. */ - static PhysicsBody* createEdgePolygon(Point* points, int count, float border = 1); + static PhysicsBody* createEdgePolygon(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgeChain shape. */ - static PhysicsBody* createEdgeChain(Point* points, int count, float border = 1); + static PhysicsBody* createEdgeChain(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); virtual void addShape(PhysicsShape* shape); diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index 0b80d9ae68..b373e0710e 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -49,7 +49,6 @@ PhysicsShape::PhysicsShape() , _area(0) , _mass(0) , _angularDamping(0) -, _density(0) , _tag(0) , _enable(true) { @@ -61,12 +60,13 @@ PhysicsShape::~PhysicsShape() CC_SAFE_DELETE(_info); } -bool PhysicsShape::init(Type type) +bool PhysicsShape::init(Type type, PhysicsMaterial material/* = MaterialDefault*/) { _info = new PhysicsShapeInfo(this); if (_info == nullptr) return false; _type = type; + _material = material; return true; } @@ -183,6 +183,14 @@ PhysicsShapeEdgeSegment::~PhysicsShapeEdgeSegment() #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +void PhysicsShape::initEnd() +{ + for (auto shape : _info->shapes) + { + cpShapeSetElasticity(shape, _material.elasticity); + cpShapeSetFriction(shape, _material.friction); + } +} void PhysicsShape::setElasticity(float elasticity) { @@ -201,10 +209,10 @@ void PhysicsShape::setFriction(float friction) } // PhysicsShapeCircle -PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeCircle* shape = new PhysicsShapeCircle(); - if (shape && shape->init(radius, density, offset)) + if (shape && shape->init(radius, material, offset)) { shape->autorelease(); return shape; @@ -214,23 +222,23 @@ PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, float density/* = 0 return nullptr; } -bool PhysicsShapeCircle::init(float radius, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeCircle::init(float radius, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(Type::CIRCLE)); + CC_BREAK_IF(!PhysicsShape::init(Type::CIRCLE, material)); cpShape* shape = cpCircleShapeNew(_info->shareBody, radius, PhysicsHelper::point2cpv(offset)); CC_BREAK_IF(shape == nullptr); - _density = density; _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); - _mass = _density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _density * _area; + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForCircle(_mass, 0, radius, PhysicsHelper::point2cpv(offset)); _info->add(shape); + initEnd(); return true; } while (false); @@ -238,10 +246,10 @@ bool PhysicsShapeCircle::init(float radius, float density/* = 0*/, Point offset } // PhysicsShapeEdgeSegment -PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(Point a, Point b, float border/* = 1*/) +PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(Point a, Point b, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgeSegment* shape = new PhysicsShapeEdgeSegment(); - if (shape && shape->init(a, b, border)) + if (shape && shape->init(a, b, material, border)) { shape->autorelease(); return shape; @@ -251,11 +259,11 @@ PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(Point a, Point b, float return nullptr; } -bool PhysicsShapeEdgeSegment::init(Point a, Point b, float border/* = 1*/) +bool PhysicsShapeEdgeSegment::init(Point a, Point b, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { do { - CC_BREAK_IF(!PhysicsShape::init(Type::EDGESEGMENT)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGESEGMENT, material)); cpShape* shape = cpSegmentShapeNew(_info->shareBody, PhysicsHelper::point2cpv(a), @@ -264,11 +272,13 @@ bool PhysicsShapeEdgeSegment::init(Point a, Point b, float border/* = 1*/) CC_BREAK_IF(shape == nullptr); - _density = PHYSICS_INFINITY; + _mass = PHYSICS_INFINITY; _angularDamping = PHYSICS_INFINITY; _info->add(shape); + initEnd(); + return true; } while (false); @@ -276,10 +286,10 @@ bool PhysicsShapeEdgeSegment::init(Point a, Point b, float border/* = 1*/) } // PhysicsShapeBox -PhysicsShapeBox* PhysicsShapeBox::create(Size size, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeBox* PhysicsShapeBox::create(Size size, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeBox* shape = new PhysicsShapeBox(); - if (shape && shape->init(size, density, offset)) + if (shape && shape->init(size, material, offset)) { shape->autorelease(); return shape; @@ -289,26 +299,24 @@ PhysicsShapeBox* PhysicsShapeBox::create(Size size, float density/* = 0*/, Point return nullptr; } -bool PhysicsShapeBox::init(Size size, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeBox::init(Size size, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(Type::BOX)); + CC_BREAK_IF(!PhysicsShape::init(Type::BOX, material)); cpShape* shape = cpBoxShapeNew(_info->shareBody, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); CC_BREAK_IF(shape == nullptr); - _density = density; _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(4, ((cpPolyShape*)shape)->verts)); - _mass = _density * _area; - if (_mass != 0) - { - _angularDamping = cpMomentForBox(_mass, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); - } + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForBox(_mass, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); _info->add(shape); + initEnd(); + return true; } while (false); @@ -316,10 +324,10 @@ bool PhysicsShapeBox::init(Size size, float density/* = 0*/, Point offset /*= Po } // PhysicsShapeCircle -PhysicsShapePolygon* PhysicsShapePolygon::create(Point* points, int count, float density/* = 0*/, Point offset/* = Point(0, 0)*/) +PhysicsShapePolygon* PhysicsShapePolygon::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapePolygon* shape = new PhysicsShapePolygon(); - if (shape && shape->init(points, count, density, offset)) + if (shape && shape->init(points, count, material, offset)) { shape->autorelease(); return shape; @@ -329,11 +337,11 @@ PhysicsShapePolygon* PhysicsShapePolygon::create(Point* points, int count, float return nullptr; } -bool PhysicsShapePolygon::init(Point* points, int count, float density/* = 0*/, Point offset /*= Point(0, 0)*/) +bool PhysicsShapePolygon::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(Type::POLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::POLYGEN, material)); cpVect* vecs = new cpVect[count]; PhysicsHelper::points2cpvs(points, vecs, count); @@ -342,16 +350,14 @@ bool PhysicsShapePolygon::init(Point* points, int count, float density/* = 0*/, CC_BREAK_IF(shape == nullptr); - _density = density; _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts)); - _mass = _density * _area; - if (_mass != 0) - { - _angularDamping = cpMomentForPoly(_mass, ((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts, PhysicsHelper::point2cpv(offset)); - } + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForPoly(_mass, ((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts, PhysicsHelper::point2cpv(offset)); _info->add(shape); + initEnd(); + return true; } while (false); @@ -359,10 +365,10 @@ bool PhysicsShapePolygon::init(Point* points, int count, float density/* = 0*/, } // PhysicsShapeEdgeBox -PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(Size size, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeEdgeBox* shape = new PhysicsShapeEdgeBox(); - if (shape && shape->init(size, border, offset)) + if (shape && shape->init(size, material, border, offset)) { shape->autorelease(); return shape; @@ -372,11 +378,11 @@ PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(Size size, float border/* = 1*/ return nullptr; } -bool PhysicsShapeEdgeBox::init(Size size, float border/* = 1*/, Point offset/*= Point(0, 0)*/) +bool PhysicsShapeEdgeBox::init(Size size, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/, Point offset/*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(Type::EDGEBOX)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEBOX, material)); cpVect vec[4] = {}; vec[0] = PhysicsHelper::point2cpv(Point(-size.width/2+offset.x, -size.height/2+offset.y)); @@ -390,8 +396,6 @@ bool PhysicsShapeEdgeBox::init(Size size, float border/* = 1*/, Point offset/*= cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[(i+1)%4], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); - cpShapeSetElasticity(shape, 1.0f); - cpShapeSetFriction(shape, 1.0f); _info->add(shape); } CC_BREAK_IF(i < 4); @@ -399,6 +403,8 @@ bool PhysicsShapeEdgeBox::init(Size size, float border/* = 1*/, Point offset/*= _mass = PHYSICS_INFINITY; _angularDamping = PHYSICS_INFINITY; + initEnd(); + return true; } while (false); @@ -406,10 +412,10 @@ bool PhysicsShapeEdgeBox::init(Size size, float border/* = 1*/, Point offset/*= } // PhysicsShapeEdgeBox -PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgePolygon* shape = new PhysicsShapeEdgePolygon(); - if (shape && shape->init(points, count, border)) + if (shape && shape->init(points, count, material, border)) { shape->autorelease(); return shape; @@ -419,12 +425,12 @@ PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(Point* points, int coun return nullptr; } -bool PhysicsShapeEdgePolygon::init(Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgePolygon::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(Type::EDGEPOLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEPOLYGEN, material)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -446,6 +452,8 @@ bool PhysicsShapeEdgePolygon::init(Point* points, int count, float border/* = 1* _mass = PHYSICS_INFINITY; _angularDamping = PHYSICS_INFINITY; + initEnd(); + return true; } while (false); @@ -455,10 +463,10 @@ bool PhysicsShapeEdgePolygon::init(Point* points, int count, float border/* = 1* } // PhysicsShapeEdgeChain -PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgeChain* shape = new PhysicsShapeEdgeChain(); - if (shape && shape->init(points, count, border)) + if (shape && shape->init(points, count, material, border)) { shape->autorelease(); return shape; @@ -468,12 +476,12 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(Point* points, int count, f return nullptr; } -bool PhysicsShapeEdgeChain::init(Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgeChain::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(Type::EDGECHAIN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGECHAIN, material)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -494,6 +502,8 @@ bool PhysicsShapeEdgeChain::init(Point* points, int count, float border/* = 1*/) _mass = PHYSICS_INFINITY; _angularDamping = PHYSICS_INFINITY; + initEnd(); + return true; } while (false); diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index aea4a9e36d..d754f6030b 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -37,7 +37,27 @@ class PhysicsShapeInfo; class PhysicsBody; class PhysicsBodyInfo; -/** + +typedef struct PhysicsMaterial +{ + float density; + float elasticity; + float friction; + + PhysicsMaterial() + : density(0.0f) + , elasticity(0.0f) + , friction(0.0f){} + + PhysicsMaterial(float density, float elasticity, float friction) + : density(density) + , elasticity(elasticity) + , friction(friction){} +}PhysicsMaterial; + +const PhysicsMaterial PHYSICSSHAPE_MATERIAL_DEFAULT = {0.0f, 1.0f, 1.0f}; + +/** * @brief A shape for body. You do not create PhysicsWorld objects directly, instead, you can view PhysicsBody to see how to create it. */ class PhysicsShape : public Object @@ -58,11 +78,7 @@ public: public: inline PhysicsBody* getBody(){ return _body; } inline Type getType() { return _type; } - inline float getMass() { return _mass; } - void setMass(float mass); inline float getArea() { return _area; } - inline float getDensity() { return _density; } - void setDensity(float density); inline float getAngularDumping() { return _angularDamping; } void setAngularDumping(float angularDumping); inline void setTag(int tag) { _tag = tag; } @@ -71,13 +87,16 @@ public: inline bool isEnable() { return _enable; } void addToBody(); + inline float getMass() { return _mass; } + void setMass(float mass); + inline float getDensity() { return _material.density; } + void setDensity(float density); void setElasticity(float elasticity); void setFriction(float friction); - - protected: - bool init(Type type); + bool init(Type type, PhysicsMaterial material); + void initEnd(); /** * @brief PhysicsShape is PhysicsBody's friend class, but all the subclasses isn't. so this method is use for subclasses to catch the bodyInfo from PhysicsBody. @@ -97,7 +116,7 @@ protected: float _area; float _mass; float _angularDamping; - float _density; + PhysicsMaterial _material; int _tag; bool _enable; @@ -109,10 +128,10 @@ protected: class PhysicsShapeCircle : public PhysicsShape { public: - static PhysicsShapeCircle* create(float radius, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapeCircle* create(float radius, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: - bool init(float radius, float density = 0, Point offset = Point(0, 0)); + bool init(float radius, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapeCircle(); @@ -125,10 +144,10 @@ protected: class PhysicsShapeBox : public PhysicsShape { public: - static PhysicsShapeBox* create(Size size, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapeBox* create(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: - bool init(Size size, float density = 0, Point offset = Point(0, 0)); + bool init(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapeBox(); @@ -141,10 +160,10 @@ protected: class PhysicsShapePolygon : public PhysicsShape { public: - static PhysicsShapePolygon* create(Point* points, int count, float density = 0, Point offset = Point(0, 0)); + static PhysicsShapePolygon* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: - bool init(Point* points, int count, float density = 0, Point offset = Point(0, 0)); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapePolygon(); @@ -157,10 +176,10 @@ protected: class PhysicsShapeEdgeSegment : public PhysicsShape { public: - static PhysicsShapeEdgeSegment* create(Point a, Point b, float border = 1); + static PhysicsShapeEdgeSegment* create(Point a, Point b, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: - bool init(Point a, Point b, float border = 1); + bool init(Point a, Point b, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgeSegment(); @@ -173,10 +192,10 @@ protected: class PhysicsShapeEdgeBox : public PhysicsShape { public: - static PhysicsShapeEdgeBox* create(Size size, float border = 0, Point offset = Point(0, 0)); + static PhysicsShapeEdgeBox* create(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 0, Point offset = Point(0, 0)); protected: - bool init(Size size, float border = 1, Point offset = Point(0, 0)); + bool init(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1, Point offset = Point(0, 0)); protected: PhysicsShapeEdgeBox(); @@ -189,10 +208,10 @@ protected: class PhysicsShapeEdgePolygon : public PhysicsShape { public: - static PhysicsShapeEdgePolygon* create(Point* points, int count, float border = 1); + static PhysicsShapeEdgePolygon* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: - bool init(Point* points, int count, float border = 1); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgePolygon(); @@ -205,10 +224,10 @@ protected: class PhysicsShapeEdgeChain : public PhysicsShape { public: - static PhysicsShapeEdgeChain* create(Point* points, int count, float border = 1); + static PhysicsShapeEdgeChain* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: - bool init(Point* points, int count, float border = 1); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgeChain(); diff --git a/cocos2dx/physics/CCPhysicsWorld.cpp b/cocos2dx/physics/CCPhysicsWorld.cpp index 6f0fa1295c..fa0c245e5e 100644 --- a/cocos2dx/physics/CCPhysicsWorld.cpp +++ b/cocos2dx/physics/CCPhysicsWorld.cpp @@ -286,7 +286,6 @@ void PhysicsWorld::debugDraw() void PhysicsWorld::setScene(Scene *scene) { _scene = scene; - scene->retain(); } void PhysicsWorld::drawWithShape(DrawNode* node, PhysicsShape* shape) @@ -413,7 +412,6 @@ PhysicsWorld::~PhysicsWorld() { CC_SAFE_DELETE(_info); CC_SAFE_RELEASE(_bodys); - CC_SAFE_RELEASE(_scene); } NS_CC_END diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index 3135e2481a..658cc606da 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -6,6 +6,7 @@ namespace { static std::function createFunctions[] = { CL(PhysicsDemoLogoSmash), + CL(PhysicsDemoPyramidStack), CL(PhysicsDemoClickAdd), }; @@ -48,10 +49,17 @@ namespace } } + +bool PhysicsTestScene::_debugDraw = false; + bool PhysicsTestScene::initTest() { #ifdef CC_USE_PHYSICS - return TestScene::initWithPhysics(); + if(TestScene::initWithPhysics()) + { + this->getPhysicsWorld()->setDebugDraw(_debugDraw); + return true; + } #else return TestScene::init(); #endif @@ -70,6 +78,12 @@ void PhysicsTestScene::runThisTest() #endif } +void PhysicsTestScene::toggleDebug() +{ + _debugDraw = !_debugDraw; + getPhysicsWorld()->setDebugDraw(_debugDraw); +} + PhysicsDemo::PhysicsDemo() : _scene(nullptr) { @@ -94,6 +108,7 @@ std::string PhysicsDemo::subtitle() void PhysicsDemo::restartCallback(Object* sender) { auto s = new PhysicsTestScene(); + s->initTest(); s->addChild( restart() ); Director::getInstance()->replaceScene(s); s->release(); @@ -102,6 +117,7 @@ void PhysicsDemo::restartCallback(Object* sender) void PhysicsDemo::nextCallback(Object* sender) { auto s = new PhysicsTestScene(); + s->initTest(); s->addChild( next() ); Director::getInstance()->replaceScene(s); s->release(); @@ -110,6 +126,7 @@ void PhysicsDemo::nextCallback(Object* sender) void PhysicsDemo::backCallback(Object* sender) { auto s = new PhysicsTestScene(); + s->initTest(); s->addChild( back() ); Director::getInstance()->replaceScene(s); s->release(); @@ -119,7 +136,10 @@ void PhysicsDemo::onEnter() { BaseTest::onEnter(); - _scene = dynamic_cast(this->getParent()); + _scene = dynamic_cast(this->getParent()); + + _spriteTexture = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100)->getTexture(); + #ifdef CC_USE_PHYSICS // menu for debug layer MenuItemFont::setFontSize(18); @@ -132,48 +152,7 @@ void PhysicsDemo::onEnter() #endif } - -void PhysicsDemo::toggleDebugCallback(Object* sender) -{ -#ifdef CC_USE_PHYSICS - if (_scene != nullptr) - { - _scene->getPhysicsWorld()->setDebugDraw(!_scene->getPhysicsWorld()->isDebugDraw()); - } -#endif -} - -void PhysicsDemoClickAdd::onEnter() -{ - PhysicsDemo::onEnter(); - -#ifdef CC_USE_PHYSICS - setTouchEnabled(true); - setAccelerometerEnabled(true); - - auto node = Node::create(); - auto body = PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size); - node->setPhysicsBody(body); - node->setPosition(VisibleRect::center()); - this->addChild(node); - - auto parent = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100); - _spriteTexture = parent->getTexture(); - - addNewSpriteAtPosition(VisibleRect::center()); - -#else - auto label = LabelTTF::create("Should define CC_USE_BOX2D or CC_USE_CHIPMUNK\n to run this test case", - "Arial", - 18); - auto size = Director::getInstance()->getWinSize(); - label->setPosition(Point(size.width/2, size.height/2)); - - addChild(label); -#endif -} - -void PhysicsDemoClickAdd::addNewSpriteAtPosition(Point p) +void PhysicsDemo::addGrossiniAtPosition(Point p, float scale/* = 1.0*/) { #ifdef CC_USE_PHYSICS CCLOG("Add sprite %0.2f x %02.f",p.x,p.y); @@ -187,13 +166,50 @@ void PhysicsDemoClickAdd::addNewSpriteAtPosition(Point p) posy = (posy % 3) * 121; auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121)); - auto body = PhysicsBody::createBox(Size(48, 108)); - sp->setPhysicsBody(body); + sp->setScale(scale); + sp->setPhysicsBody(PhysicsBody::createBox(Size(48.0f * scale, 108.0f * scale))); this->addChild(sp); sp->setPosition(p); #endif } + +void PhysicsDemo::toggleDebugCallback(Object* sender) +{ +#ifdef CC_USE_PHYSICS + if (_scene != nullptr) + { + _scene->toggleDebug(); + } +#endif +} + +void PhysicsDemoClickAdd::onEnter() +{ + PhysicsDemo::onEnter(); + +#ifdef CC_USE_PHYSICS + setTouchEnabled(true); + setAccelerometerEnabled(true); + + auto node = Node::create(); + node->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size)); + node->setPosition(VisibleRect::center()); + this->addChild(node); + + addGrossiniAtPosition(VisibleRect::center()); + +#else + auto label = LabelTTF::create("Should define CC_USE_BOX2D or CC_USE_CHIPMUNK\n to run this test case", + "Arial", + 18); + auto size = Director::getInstance()->getWinSize(); + label->setPosition(Point(size.width/2, size.height/2)); + + addChild(label); +#endif +} + std::string PhysicsDemoClickAdd::subtitle() { return "multi touch to add grossini"; @@ -207,7 +223,7 @@ void PhysicsDemoClickAdd::onTouchesEnded(const std::vector& touches, Eve { auto location = touch->getLocation(); - addNewSpriteAtPosition( location ); + addGrossiniAtPosition( location ); } } @@ -289,16 +305,13 @@ namespace Node* PhysicsDemoLogoSmash::makeBall(float x, float y) { - Sprite* ball = Sprite::create("Images/ball.png"); + auto ball = Sprite::create("Images/ball.png"); ball->setScale(0.1); - PhysicsBody* body = PhysicsBody::createCircle(0.95); + auto body = PhysicsBody::createCircle(0.95, PhysicsMaterial(1, 0, 0)); body->setMass(1.0); body->setAngularDamping(PHYSICS_INFINITY); - body->getShape()->setElasticity(0); - body->getShape()->setFriction(0); - //body->setDynamic(false); ball->setPhysicsBody(body); @@ -310,7 +323,6 @@ Node* PhysicsDemoLogoSmash::makeBall(float x, float y) void PhysicsDemoLogoSmash::onEnter() { PhysicsDemo::onEnter(); - _draw = DrawNode::create(); _scene->getPhysicsWorld()->setGravity(Point(0, 0)); //addChild(makeBall(200, 200)); @@ -330,13 +342,11 @@ void PhysicsDemoLogoSmash::onEnter() } - Sprite* bullet = Sprite::create("Images/ball.png"); + auto bullet = Sprite::create("Images/ball.png"); bullet->setScale(0.5); - PhysicsBody* body = PhysicsBody::createCircle(8, PHYSICS_INFINITY); + auto body = PhysicsBody::createCircle(8, PhysicsMaterial(PHYSICS_INFINITY, 0, 0)); body->setVelocity(Point(400, 0)); - body->getShape()->setElasticity(0); - body->getShape()->setFriction(0); bullet->setPhysicsBody(body); bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2)); @@ -347,4 +357,40 @@ void PhysicsDemoLogoSmash::onEnter() std::string PhysicsDemoLogoSmash::title() { return "Logo Smash"; +} + +void PhysicsDemoPyramidStack::onEnter() +{ + PhysicsDemo::onEnter(); + + auto node = Node::create(); + node->setPhysicsBody(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Point(0, 50), VisibleRect::rightBottom() + Point(0, 50))); + this->addChild(node); + + auto ball = Sprite::create("Images/ball.png"); + ball->setScale(1); + ball->setPhysicsBody(PhysicsBody::createCircle(10)); + ball->setPosition(VisibleRect::bottom() + Point(0, 60)); + this->addChild(ball); + + for(int i=0; i<14; i++){ + for(int j=0; j<=i; j++){ + addGrossiniAtPosition(VisibleRect::bottom() + Point((i/2 - j) * 11, (14 - i) * 23 + 100), 0.2); + } + } +} +std::string PhysicsDemoPyramidStack::title() +{ + return "Pyramid Stack"; +} + + +void PhysicsDemoPlink::onEnter() +{ + PhysicsDemo::onEnter(); +} + +std::string PhysicsDemoPlink::title() +{ + return "Plink"; } \ No newline at end of file diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h index cf63471998..c75431a852 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h @@ -11,12 +11,17 @@ class PhysicsTestScene : public TestScene public: virtual bool initTest() override; virtual void runThisTest(); + + void toggleDebug(); + +private: + static bool _debugDraw; }; class PhysicsDemo : public BaseTest { protected: - Scene* _scene; + PhysicsTestScene* _scene; public: PhysicsDemo(); @@ -30,6 +35,11 @@ public: void nextCallback(Object* sender); void backCallback(Object* sender); void toggleDebugCallback(Object* sender); + + void addGrossiniAtPosition(Point p, float scale = 1.0); + +private: + Texture2D* _spriteTexture; // weak ref }; class PhysicsDemoClickAdd : public PhysicsDemo @@ -38,13 +48,8 @@ public: void onEnter() override; std::string subtitle() override; - void addNewSpriteAtPosition(Point p); - void onTouchesEnded(const std::vector& touches, Event* event) override; void onAcceleration(Acceleration* acc, Event* event) override; - -private: - Texture2D* _spriteTexture; // weak ref }; class PhysicsDemoLogoSmash : public PhysicsDemo @@ -54,9 +59,20 @@ public: std::string title() override; Node* makeBall(float x, float y); - -private: - DrawNode* _draw; +}; + +class PhysicsDemoPyramidStack : public PhysicsDemo +{ +public: + void onEnter() override; + std::string title() override; +}; + +class PhysicsDemoPlink : public PhysicsDemo +{ +public: + void onEnter() override; + std::string title() override; }; #endif From 7756c7765100bf0ac8ac25b0c5cda0bf81946ce3 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Wed, 9 Oct 2013 18:09:24 +0800 Subject: [PATCH 036/116] issues #2899:Fix application will crash when back to background on Android. --- cocos2dx/platform/android/jni/JniHelper.cpp | 11 ++++++++++- cocos2dx/platform/android/jni/JniHelper.h | 1 + cocos2dx/platform/android/nativeactivity.cpp | 6 +++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cocos2dx/platform/android/jni/JniHelper.cpp b/cocos2dx/platform/android/jni/JniHelper.cpp index 852208afc3..22a3807df2 100644 --- a/cocos2dx/platform/android/jni/JniHelper.cpp +++ b/cocos2dx/platform/android/jni/JniHelper.cpp @@ -58,6 +58,8 @@ namespace cocos2d { jobject JniHelper::classloader = NULL; JNIEnv* JniHelper::env = NULL; + static pthread_key_t thread_key; + JavaVM* JniHelper::getJavaVM() { pthread_t thisthread = pthread_self(); LOGD("JniHelper::getJavaVM(), pthread_self() = %X", thisthread); @@ -72,6 +74,10 @@ namespace cocos2d { JniHelper::cacheEnv(javaVM); } + void JniHelper::detach_current_thread (void *env) { + _psJavaVM->DetachCurrentThread(); + } + bool JniHelper::cacheEnv(JavaVM* jvm) { JNIEnv* _env = NULL; // get jni environment @@ -89,7 +95,8 @@ namespace cocos2d { // TODO : If calling AttachCurrentThread() on a native thread // must call DetachCurrentThread() in future. // see: http://developer.android.com/guide/practices/design/jni.html - + + pthread_key_create (&thread_key, JniHelper::detach_current_thread); if (jvm->AttachCurrentThread(&_env, NULL) < 0) { LOGD("Failed to get the environment using AttachCurrentThread()"); @@ -99,6 +106,8 @@ namespace cocos2d { } else { // Success : Attached and obtained JNIEnv! JniHelper::env = _env; + if (pthread_getspecific(thread_key) == NULL) + pthread_setspecific(thread_key, _env); return true; } diff --git a/cocos2dx/platform/android/jni/JniHelper.h b/cocos2dx/platform/android/jni/JniHelper.h index 01405d9559..fe1bf38814 100644 --- a/cocos2dx/platform/android/jni/JniHelper.h +++ b/cocos2dx/platform/android/jni/JniHelper.h @@ -60,6 +60,7 @@ public: static jobject classloader; private: + static void detach_current_thread (void *env); static bool cacheEnv(JavaVM* jvm); static bool getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo, diff --git a/cocos2dx/platform/android/nativeactivity.cpp b/cocos2dx/platform/android/nativeactivity.cpp index c5d387433a..aa0f8f8199 100644 --- a/cocos2dx/platform/android/nativeactivity.cpp +++ b/cocos2dx/platform/android/nativeactivity.cpp @@ -215,10 +215,10 @@ static cocos_dimensions engine_init_display(struct engine* engine) { /** * Invoke the dispatching of the next bunch of Runnables in the Java-Land */ +static bool initialized = false; static void dispatch_pending_runnables() { static cocos2d::JniMethodInfo info; - static bool initialized = false; - + if (!initialized) { initialized = cocos2d::JniHelper::getStaticMethodInfo( info, @@ -652,7 +652,7 @@ void android_main(struct android_app* state) { engine_term_display(&engine); memset(&engine, 0, sizeof(engine)); - + initialized = false; return; } } From a17f141e7dd70ea6e031b3fb5037f76d452b6903 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Thu, 10 Oct 2013 10:28:49 +0800 Subject: [PATCH 037/116] issues #2914:removeSpriteFramesFromFile() crashes if file doesn't exist --- cocos2dx/sprite_nodes/CCSpriteFrameCache.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cocos2dx/sprite_nodes/CCSpriteFrameCache.cpp b/cocos2dx/sprite_nodes/CCSpriteFrameCache.cpp index 945cd30f32..1d19773c60 100644 --- a/cocos2dx/sprite_nodes/CCSpriteFrameCache.cpp +++ b/cocos2dx/sprite_nodes/CCSpriteFrameCache.cpp @@ -344,7 +344,11 @@ void SpriteFrameCache::removeSpriteFramesFromFile(const char* plist) { std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plist); Dictionary* dict = Dictionary::createWithContentsOfFileThreadSafe(fullPath.c_str()); - + if (dict == nullptr) + { + CCLOG("cocos2d:SpriteFrameCache:removeSpriteFramesFromFile: create dict by %s fail.",plist); + return; + } removeSpriteFramesFromDictionary((Dictionary*)dict); // remove it from the cache From b5ee16399c0285f0e80ebb3a10575ed4f103e066 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 10 Oct 2013 11:09:09 +0800 Subject: [PATCH 038/116] =?UTF-8?q?issue=20#2768:Modify=20the=20linux=20ma?= =?UTF-8?q?ke=20files=20of=20the=20liblua=20=E3=80=81the=20testlua=20and?= =?UTF-8?q?=20hellolua=20projects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- samples/Lua/HelloLua/proj.linux/Makefile | 2 +- samples/Lua/TestLua/proj.linux/Makefile | 2 +- scripting/lua/proj.linux/Makefile | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/Lua/HelloLua/proj.linux/Makefile b/samples/Lua/HelloLua/proj.linux/Makefile index 9c80a175dd..f0b63ea010 100644 --- a/samples/Lua/HelloLua/proj.linux/Makefile +++ b/samples/Lua/HelloLua/proj.linux/Makefile @@ -10,7 +10,7 @@ INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ SOURCES = main.cpp ../Classes/AppDelegate.cpp SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -lextension -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so $(LIB_DIR)/libbox2d.so +COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk diff --git a/samples/Lua/TestLua/proj.linux/Makefile b/samples/Lua/TestLua/proj.linux/Makefile index 6d73226774..cb88cc9a93 100644 --- a/samples/Lua/TestLua/proj.linux/Makefile +++ b/samples/Lua/TestLua/proj.linux/Makefile @@ -9,7 +9,7 @@ INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ SOURCES = main.cpp ../Classes/AppDelegate.cpp SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so $(LIB_DIR)/libbox2d.so +COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so include $(COCOS_ROOT)/cocos2dx/proj.linux/cocos2dx.mk diff --git a/scripting/lua/proj.linux/Makefile b/scripting/lua/proj.linux/Makefile index b718baf883..3e49658d56 100644 --- a/scripting/lua/proj.linux/Makefile +++ b/scripting/lua/proj.linux/Makefile @@ -59,6 +59,7 @@ include ../../../cocos2dx/proj.linux/cocos2dx.mk TARGET := $(LIB_DIR)/$(TARGET) SHAREDLIBS += -lextension +STATICLIBS += $(LIB_DIR)/libbox2d.a all: $(TARGET) From a8f0c99abf82f707c24071f31503fe41f3759d25 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Thu, 10 Oct 2013 11:12:33 +0800 Subject: [PATCH 039/116] Fix miss project configuration for CoreMotion. --- samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index dc39ae6bd3..ec33bf839a 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -d846dfb9965fecfad1f6fe6190516035158c4d53 \ No newline at end of file +381c282bed409f4b41a82505460d4d6c84ba70ab \ No newline at end of file From 78e3624b0bd7c4fa1dd1ba8fc49334f184301b77 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 10 Oct 2013 11:15:22 +0800 Subject: [PATCH 040/116] Update CHANGELOG[ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 81416cfc94..6a3d593beb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ cocos2d-x-3.0alpha1 @??? 2013 [FIX] Texture: use CCLOG to log when a texture is being decoded in software [FIX] Spine: fix memory leaks [FIX] fixed a memory leak in XMLHTTPRequest.cpp + [FIX] removeSpriteFramesFromFile() crashes if file doesn't exist. [Android] [FIX] Added EGL_RENDERABLE_TYPE to OpenGL attributes [NEW] Added Cocos2dxHelper.runOnGLThread(Runnable) again From 6b400dd4eca4c6643562b0fbc85b6706c13fb332 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Thu, 10 Oct 2013 11:30:42 +0800 Subject: [PATCH 041/116] rename some variable --- cocos2dx/platform/android/jni/JniHelper.cpp | 8 ++++---- cocos2dx/platform/android/nativeactivity.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cocos2dx/platform/android/jni/JniHelper.cpp b/cocos2dx/platform/android/jni/JniHelper.cpp index 22a3807df2..ab3bfc3855 100644 --- a/cocos2dx/platform/android/jni/JniHelper.cpp +++ b/cocos2dx/platform/android/jni/JniHelper.cpp @@ -58,7 +58,7 @@ namespace cocos2d { jobject JniHelper::classloader = NULL; JNIEnv* JniHelper::env = NULL; - static pthread_key_t thread_key; + static pthread_key_t s_threadKey; JavaVM* JniHelper::getJavaVM() { pthread_t thisthread = pthread_self(); @@ -96,7 +96,7 @@ namespace cocos2d { // must call DetachCurrentThread() in future. // see: http://developer.android.com/guide/practices/design/jni.html - pthread_key_create (&thread_key, JniHelper::detach_current_thread); + pthread_key_create (&s_threadKey, JniHelper::detach_current_thread); if (jvm->AttachCurrentThread(&_env, NULL) < 0) { LOGD("Failed to get the environment using AttachCurrentThread()"); @@ -106,8 +106,8 @@ namespace cocos2d { } else { // Success : Attached and obtained JNIEnv! JniHelper::env = _env; - if (pthread_getspecific(thread_key) == NULL) - pthread_setspecific(thread_key, _env); + if (pthread_getspecific(s_threadKey) == NULL) + pthread_setspecific(s_threadKey, _env); return true; } diff --git a/cocos2dx/platform/android/nativeactivity.cpp b/cocos2dx/platform/android/nativeactivity.cpp index aa0f8f8199..b591953fb8 100644 --- a/cocos2dx/platform/android/nativeactivity.cpp +++ b/cocos2dx/platform/android/nativeactivity.cpp @@ -215,19 +215,19 @@ static cocos_dimensions engine_init_display(struct engine* engine) { /** * Invoke the dispatching of the next bunch of Runnables in the Java-Land */ -static bool initialized = false; +static bool s_methodInitialized = false; static void dispatch_pending_runnables() { static cocos2d::JniMethodInfo info; - if (!initialized) { - initialized = cocos2d::JniHelper::getStaticMethodInfo( + if (!s_methodInitialized) { + s_methodInitialized = cocos2d::JniHelper::getStaticMethodInfo( info, "org/cocos2dx/lib/Cocos2dxHelper", "dispatchPendingRunnables", "()V" ); - if (!initialized) { + if (!s_methodInitialized) { LOGW("Unable to dispatch pending Runnables!"); return; } @@ -652,7 +652,7 @@ void android_main(struct android_app* state) { engine_term_display(&engine); memset(&engine, 0, sizeof(engine)); - initialized = false; + s_methodInitialized = false; return; } } From a02b2b6834a4cc0b05940956b738edbe6967ee12 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 10 Oct 2013 13:55:22 +0800 Subject: [PATCH 042/116] Update CHANGELOG [ci skip] --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 6a3d593beb..b9641d1f71 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ cocos2d-x-3.0alpha1 @??? 2013 [Javascript binding] [FIX] Fixed a memory leak in ScriptingCore::runScript() [FIX] sys.localStorage.getItem() does not support non-ascii string. +[Lua Binding] + [FIX] Added Armature lua binding and added test samples. cocos2d-x-3.0alpha0 @Sep.19 2013 [all platforms] From c46f74b084ad2a9fd41bb3fede7885b11ec568aa Mon Sep 17 00:00:00 2001 From: minggo Date: Thu, 10 Oct 2013 14:06:53 +0800 Subject: [PATCH 043/116] issue 2905:SimpleAudioEngine -> audio --- {CocosDenshion => audio}/android/Android.mk | 0 {CocosDenshion => audio}/android/ccdandroidUtils.cpp | 0 {CocosDenshion => audio}/android/ccdandroidUtils.h | 0 {CocosDenshion => audio}/android/cddSimpleAudioEngine.cpp | 0 .../android/jni/cddandroidAndroidJavaEngine.cpp | 0 .../android/jni/cddandroidAndroidJavaEngine.h | 0 {CocosDenshion => audio}/android/opensl/OpenSLEngine.cpp | 0 {CocosDenshion => audio}/android/opensl/OpenSLEngine.h | 0 .../android/opensl/SimpleAudioEngineOpenSL.cpp | 0 {CocosDenshion => audio}/android/opensl/SimpleAudioEngineOpenSL.h | 0 .../android/opensl/cddandroidOpenSLEngine.cpp | 0 {CocosDenshion => audio}/android/opensl/cddandroidOpenSLEngine.h | 0 {CocosDenshion => audio}/emscripten/SimpleAudioEngine.cpp | 0 {CocosDenshion => audio}/include/Export.h | 0 {CocosDenshion => audio}/include/SimpleAudioEngine.h | 0 {CocosDenshion => audio}/ios/CDAudioManager.h | 0 {CocosDenshion => audio}/ios/CDAudioManager.m | 0 {CocosDenshion => audio}/ios/CDConfig.h | 0 {CocosDenshion => audio}/ios/CDOpenALSupport.h | 0 {CocosDenshion => audio}/ios/CDOpenALSupport.m | 0 {CocosDenshion => audio}/ios/CocosDenshion.h | 0 {CocosDenshion => audio}/ios/CocosDenshion.m | 0 {CocosDenshion => audio}/ios/SimpleAudioEngine.mm | 0 {CocosDenshion => audio}/ios/SimpleAudioEngine_objc.h | 0 {CocosDenshion => audio}/ios/SimpleAudioEngine_objc.m | 0 {CocosDenshion => audio}/linux/AudioPlayer.h | 0 {CocosDenshion => audio}/linux/FmodAudioPlayer.cpp | 0 {CocosDenshion => audio}/linux/FmodAudioPlayer.h | 0 {CocosDenshion => audio}/linux/SimpleAudioEngineFMOD.cpp | 0 {CocosDenshion => audio}/mac/CDAudioManager.h | 0 {CocosDenshion => audio}/mac/CDAudioManager.m | 0 {CocosDenshion => audio}/mac/CDConfig.h | 0 {CocosDenshion => audio}/mac/CDOpenALSupport.h | 0 {CocosDenshion => audio}/mac/CDOpenALSupport.m | 0 {CocosDenshion => audio}/mac/CDXMacOSXSupport.h | 0 {CocosDenshion => audio}/mac/CDXMacOSXSupport.mm | 0 {CocosDenshion => audio}/mac/CocosDenshion.h | 0 {CocosDenshion => audio}/mac/CocosDenshion.m | 0 {CocosDenshion => audio}/mac/SimpleAudioEngine.mm | 0 {CocosDenshion => audio}/mac/SimpleAudioEngine_objc.h | 0 {CocosDenshion => audio}/mac/SimpleAudioEngine_objc.m | 0 {CocosDenshion => audio}/openal/OpenALDecoder.cpp | 0 {CocosDenshion => audio}/openal/OpenALDecoder.h | 0 {CocosDenshion => audio}/openal/SimpleAudioEngineOpenAL.cpp | 0 {CocosDenshion => audio}/proj.emscripten/Makefile | 0 .../proj.ios/CocosDenshion.xcodeproj/project.pbxproj | 0 {CocosDenshion => audio}/proj.linux/.cproject | 0 {CocosDenshion => audio}/proj.linux/.project | 0 {CocosDenshion => audio}/proj.linux/CocosDenshion.prf | 0 {CocosDenshion => audio}/proj.linux/Makefile | 0 .../proj.mac/CocosDenshion.xcodeproj/project.pbxproj | 0 {CocosDenshion => audio}/proj.nacl/Makefile | 0 {CocosDenshion => audio}/proj.qt5/cocosdenshion.pro | 0 {CocosDenshion => audio}/proj.tizen/.cproject | 0 {CocosDenshion => audio}/proj.tizen/.project | 0 {CocosDenshion => audio}/proj.tizen/src/placeholder.txt | 0 {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj | 0 {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj.filters | 0 {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj.user | 0 {CocosDenshion => audio}/qt5/SimpleAudioEngineQt5.cpp | 0 {CocosDenshion => audio}/third_party/fmod/Makefile | 0 .../third_party/fmod/api/inc/fmod.h.REMOVED.git-id | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmod.hpp | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_codec.h | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_dsp.h | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_errors.h | 0 .../third_party/fmod/api/inc/fmod_memoryinfo.h | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_output.h | 0 {CocosDenshion => audio}/third_party/fmod/api/inc/fmodlinux.h | 0 .../third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id | 0 .../third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id | 0 .../third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id | 0 .../third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id | 0 {CocosDenshion => audio}/third_party/fmod/lib64/Makefile | 0 .../third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id | 0 {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod.hpp | 0 .../third_party/fmod/lib64/api/inc/fmod_codec.h | 0 .../third_party/fmod/lib64/api/inc/fmod_dsp.h | 0 .../third_party/fmod/lib64/api/inc/fmod_errors.h | 0 .../third_party/fmod/lib64/api/inc/fmod_memoryinfo.h | 0 .../third_party/fmod/lib64/api/inc/fmod_output.h | 0 .../third_party/fmod/lib64/api/inc/fmodlinux.h | 0 .../fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id | 0 .../third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id | 0 .../fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id | 0 .../third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id | 0 {CocosDenshion => audio}/win32/MciPlayer.cpp | 0 {CocosDenshion => audio}/win32/MciPlayer.h | 0 {CocosDenshion => audio}/win32/SimpleAudioEngine.cpp | 0 89 files changed, 0 insertions(+), 0 deletions(-) rename {CocosDenshion => audio}/android/Android.mk (100%) rename {CocosDenshion => audio}/android/ccdandroidUtils.cpp (100%) rename {CocosDenshion => audio}/android/ccdandroidUtils.h (100%) rename {CocosDenshion => audio}/android/cddSimpleAudioEngine.cpp (100%) rename {CocosDenshion => audio}/android/jni/cddandroidAndroidJavaEngine.cpp (100%) rename {CocosDenshion => audio}/android/jni/cddandroidAndroidJavaEngine.h (100%) rename {CocosDenshion => audio}/android/opensl/OpenSLEngine.cpp (100%) rename {CocosDenshion => audio}/android/opensl/OpenSLEngine.h (100%) rename {CocosDenshion => audio}/android/opensl/SimpleAudioEngineOpenSL.cpp (100%) rename {CocosDenshion => audio}/android/opensl/SimpleAudioEngineOpenSL.h (100%) rename {CocosDenshion => audio}/android/opensl/cddandroidOpenSLEngine.cpp (100%) rename {CocosDenshion => audio}/android/opensl/cddandroidOpenSLEngine.h (100%) rename {CocosDenshion => audio}/emscripten/SimpleAudioEngine.cpp (100%) rename {CocosDenshion => audio}/include/Export.h (100%) rename {CocosDenshion => audio}/include/SimpleAudioEngine.h (100%) rename {CocosDenshion => audio}/ios/CDAudioManager.h (100%) rename {CocosDenshion => audio}/ios/CDAudioManager.m (100%) rename {CocosDenshion => audio}/ios/CDConfig.h (100%) rename {CocosDenshion => audio}/ios/CDOpenALSupport.h (100%) rename {CocosDenshion => audio}/ios/CDOpenALSupport.m (100%) rename {CocosDenshion => audio}/ios/CocosDenshion.h (100%) rename {CocosDenshion => audio}/ios/CocosDenshion.m (100%) rename {CocosDenshion => audio}/ios/SimpleAudioEngine.mm (100%) rename {CocosDenshion => audio}/ios/SimpleAudioEngine_objc.h (100%) rename {CocosDenshion => audio}/ios/SimpleAudioEngine_objc.m (100%) rename {CocosDenshion => audio}/linux/AudioPlayer.h (100%) rename {CocosDenshion => audio}/linux/FmodAudioPlayer.cpp (100%) rename {CocosDenshion => audio}/linux/FmodAudioPlayer.h (100%) rename {CocosDenshion => audio}/linux/SimpleAudioEngineFMOD.cpp (100%) rename {CocosDenshion => audio}/mac/CDAudioManager.h (100%) rename {CocosDenshion => audio}/mac/CDAudioManager.m (100%) rename {CocosDenshion => audio}/mac/CDConfig.h (100%) rename {CocosDenshion => audio}/mac/CDOpenALSupport.h (100%) rename {CocosDenshion => audio}/mac/CDOpenALSupport.m (100%) rename {CocosDenshion => audio}/mac/CDXMacOSXSupport.h (100%) rename {CocosDenshion => audio}/mac/CDXMacOSXSupport.mm (100%) rename {CocosDenshion => audio}/mac/CocosDenshion.h (100%) rename {CocosDenshion => audio}/mac/CocosDenshion.m (100%) rename {CocosDenshion => audio}/mac/SimpleAudioEngine.mm (100%) rename {CocosDenshion => audio}/mac/SimpleAudioEngine_objc.h (100%) rename {CocosDenshion => audio}/mac/SimpleAudioEngine_objc.m (100%) rename {CocosDenshion => audio}/openal/OpenALDecoder.cpp (100%) rename {CocosDenshion => audio}/openal/OpenALDecoder.h (100%) rename {CocosDenshion => audio}/openal/SimpleAudioEngineOpenAL.cpp (100%) rename {CocosDenshion => audio}/proj.emscripten/Makefile (100%) rename {CocosDenshion => audio}/proj.ios/CocosDenshion.xcodeproj/project.pbxproj (100%) rename {CocosDenshion => audio}/proj.linux/.cproject (100%) rename {CocosDenshion => audio}/proj.linux/.project (100%) rename {CocosDenshion => audio}/proj.linux/CocosDenshion.prf (100%) rename {CocosDenshion => audio}/proj.linux/Makefile (100%) rename {CocosDenshion => audio}/proj.mac/CocosDenshion.xcodeproj/project.pbxproj (100%) rename {CocosDenshion => audio}/proj.nacl/Makefile (100%) rename {CocosDenshion => audio}/proj.qt5/cocosdenshion.pro (100%) rename {CocosDenshion => audio}/proj.tizen/.cproject (100%) rename {CocosDenshion => audio}/proj.tizen/.project (100%) rename {CocosDenshion => audio}/proj.tizen/src/placeholder.txt (100%) rename {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj (100%) rename {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj.filters (100%) rename {CocosDenshion => audio}/proj.win32/CocosDenshion.vcxproj.user (100%) rename {CocosDenshion => audio}/qt5/SimpleAudioEngineQt5.cpp (100%) rename {CocosDenshion => audio}/third_party/fmod/Makefile (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod.h.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod.hpp (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_codec.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_dsp.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_errors.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_memoryinfo.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmod_output.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/inc/fmodlinux.h (100%) rename {CocosDenshion => audio}/third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/Makefile (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod.hpp (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod_codec.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod_dsp.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod_errors.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod_memoryinfo.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmod_output.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/inc/fmodlinux.h (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id (100%) rename {CocosDenshion => audio}/win32/MciPlayer.cpp (100%) rename {CocosDenshion => audio}/win32/MciPlayer.h (100%) rename {CocosDenshion => audio}/win32/SimpleAudioEngine.cpp (100%) diff --git a/CocosDenshion/android/Android.mk b/audio/android/Android.mk similarity index 100% rename from CocosDenshion/android/Android.mk rename to audio/android/Android.mk diff --git a/CocosDenshion/android/ccdandroidUtils.cpp b/audio/android/ccdandroidUtils.cpp similarity index 100% rename from CocosDenshion/android/ccdandroidUtils.cpp rename to audio/android/ccdandroidUtils.cpp diff --git a/CocosDenshion/android/ccdandroidUtils.h b/audio/android/ccdandroidUtils.h similarity index 100% rename from CocosDenshion/android/ccdandroidUtils.h rename to audio/android/ccdandroidUtils.h diff --git a/CocosDenshion/android/cddSimpleAudioEngine.cpp b/audio/android/cddSimpleAudioEngine.cpp similarity index 100% rename from CocosDenshion/android/cddSimpleAudioEngine.cpp rename to audio/android/cddSimpleAudioEngine.cpp diff --git a/CocosDenshion/android/jni/cddandroidAndroidJavaEngine.cpp b/audio/android/jni/cddandroidAndroidJavaEngine.cpp similarity index 100% rename from CocosDenshion/android/jni/cddandroidAndroidJavaEngine.cpp rename to audio/android/jni/cddandroidAndroidJavaEngine.cpp diff --git a/CocosDenshion/android/jni/cddandroidAndroidJavaEngine.h b/audio/android/jni/cddandroidAndroidJavaEngine.h similarity index 100% rename from CocosDenshion/android/jni/cddandroidAndroidJavaEngine.h rename to audio/android/jni/cddandroidAndroidJavaEngine.h diff --git a/CocosDenshion/android/opensl/OpenSLEngine.cpp b/audio/android/opensl/OpenSLEngine.cpp similarity index 100% rename from CocosDenshion/android/opensl/OpenSLEngine.cpp rename to audio/android/opensl/OpenSLEngine.cpp diff --git a/CocosDenshion/android/opensl/OpenSLEngine.h b/audio/android/opensl/OpenSLEngine.h similarity index 100% rename from CocosDenshion/android/opensl/OpenSLEngine.h rename to audio/android/opensl/OpenSLEngine.h diff --git a/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp b/audio/android/opensl/SimpleAudioEngineOpenSL.cpp similarity index 100% rename from CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp rename to audio/android/opensl/SimpleAudioEngineOpenSL.cpp diff --git a/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.h b/audio/android/opensl/SimpleAudioEngineOpenSL.h similarity index 100% rename from CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.h rename to audio/android/opensl/SimpleAudioEngineOpenSL.h diff --git a/CocosDenshion/android/opensl/cddandroidOpenSLEngine.cpp b/audio/android/opensl/cddandroidOpenSLEngine.cpp similarity index 100% rename from CocosDenshion/android/opensl/cddandroidOpenSLEngine.cpp rename to audio/android/opensl/cddandroidOpenSLEngine.cpp diff --git a/CocosDenshion/android/opensl/cddandroidOpenSLEngine.h b/audio/android/opensl/cddandroidOpenSLEngine.h similarity index 100% rename from CocosDenshion/android/opensl/cddandroidOpenSLEngine.h rename to audio/android/opensl/cddandroidOpenSLEngine.h diff --git a/CocosDenshion/emscripten/SimpleAudioEngine.cpp b/audio/emscripten/SimpleAudioEngine.cpp similarity index 100% rename from CocosDenshion/emscripten/SimpleAudioEngine.cpp rename to audio/emscripten/SimpleAudioEngine.cpp diff --git a/CocosDenshion/include/Export.h b/audio/include/Export.h similarity index 100% rename from CocosDenshion/include/Export.h rename to audio/include/Export.h diff --git a/CocosDenshion/include/SimpleAudioEngine.h b/audio/include/SimpleAudioEngine.h similarity index 100% rename from CocosDenshion/include/SimpleAudioEngine.h rename to audio/include/SimpleAudioEngine.h diff --git a/CocosDenshion/ios/CDAudioManager.h b/audio/ios/CDAudioManager.h similarity index 100% rename from CocosDenshion/ios/CDAudioManager.h rename to audio/ios/CDAudioManager.h diff --git a/CocosDenshion/ios/CDAudioManager.m b/audio/ios/CDAudioManager.m similarity index 100% rename from CocosDenshion/ios/CDAudioManager.m rename to audio/ios/CDAudioManager.m diff --git a/CocosDenshion/ios/CDConfig.h b/audio/ios/CDConfig.h similarity index 100% rename from CocosDenshion/ios/CDConfig.h rename to audio/ios/CDConfig.h diff --git a/CocosDenshion/ios/CDOpenALSupport.h b/audio/ios/CDOpenALSupport.h similarity index 100% rename from CocosDenshion/ios/CDOpenALSupport.h rename to audio/ios/CDOpenALSupport.h diff --git a/CocosDenshion/ios/CDOpenALSupport.m b/audio/ios/CDOpenALSupport.m similarity index 100% rename from CocosDenshion/ios/CDOpenALSupport.m rename to audio/ios/CDOpenALSupport.m diff --git a/CocosDenshion/ios/CocosDenshion.h b/audio/ios/CocosDenshion.h similarity index 100% rename from CocosDenshion/ios/CocosDenshion.h rename to audio/ios/CocosDenshion.h diff --git a/CocosDenshion/ios/CocosDenshion.m b/audio/ios/CocosDenshion.m similarity index 100% rename from CocosDenshion/ios/CocosDenshion.m rename to audio/ios/CocosDenshion.m diff --git a/CocosDenshion/ios/SimpleAudioEngine.mm b/audio/ios/SimpleAudioEngine.mm similarity index 100% rename from CocosDenshion/ios/SimpleAudioEngine.mm rename to audio/ios/SimpleAudioEngine.mm diff --git a/CocosDenshion/ios/SimpleAudioEngine_objc.h b/audio/ios/SimpleAudioEngine_objc.h similarity index 100% rename from CocosDenshion/ios/SimpleAudioEngine_objc.h rename to audio/ios/SimpleAudioEngine_objc.h diff --git a/CocosDenshion/ios/SimpleAudioEngine_objc.m b/audio/ios/SimpleAudioEngine_objc.m similarity index 100% rename from CocosDenshion/ios/SimpleAudioEngine_objc.m rename to audio/ios/SimpleAudioEngine_objc.m diff --git a/CocosDenshion/linux/AudioPlayer.h b/audio/linux/AudioPlayer.h similarity index 100% rename from CocosDenshion/linux/AudioPlayer.h rename to audio/linux/AudioPlayer.h diff --git a/CocosDenshion/linux/FmodAudioPlayer.cpp b/audio/linux/FmodAudioPlayer.cpp similarity index 100% rename from CocosDenshion/linux/FmodAudioPlayer.cpp rename to audio/linux/FmodAudioPlayer.cpp diff --git a/CocosDenshion/linux/FmodAudioPlayer.h b/audio/linux/FmodAudioPlayer.h similarity index 100% rename from CocosDenshion/linux/FmodAudioPlayer.h rename to audio/linux/FmodAudioPlayer.h diff --git a/CocosDenshion/linux/SimpleAudioEngineFMOD.cpp b/audio/linux/SimpleAudioEngineFMOD.cpp similarity index 100% rename from CocosDenshion/linux/SimpleAudioEngineFMOD.cpp rename to audio/linux/SimpleAudioEngineFMOD.cpp diff --git a/CocosDenshion/mac/CDAudioManager.h b/audio/mac/CDAudioManager.h similarity index 100% rename from CocosDenshion/mac/CDAudioManager.h rename to audio/mac/CDAudioManager.h diff --git a/CocosDenshion/mac/CDAudioManager.m b/audio/mac/CDAudioManager.m similarity index 100% rename from CocosDenshion/mac/CDAudioManager.m rename to audio/mac/CDAudioManager.m diff --git a/CocosDenshion/mac/CDConfig.h b/audio/mac/CDConfig.h similarity index 100% rename from CocosDenshion/mac/CDConfig.h rename to audio/mac/CDConfig.h diff --git a/CocosDenshion/mac/CDOpenALSupport.h b/audio/mac/CDOpenALSupport.h similarity index 100% rename from CocosDenshion/mac/CDOpenALSupport.h rename to audio/mac/CDOpenALSupport.h diff --git a/CocosDenshion/mac/CDOpenALSupport.m b/audio/mac/CDOpenALSupport.m similarity index 100% rename from CocosDenshion/mac/CDOpenALSupport.m rename to audio/mac/CDOpenALSupport.m diff --git a/CocosDenshion/mac/CDXMacOSXSupport.h b/audio/mac/CDXMacOSXSupport.h similarity index 100% rename from CocosDenshion/mac/CDXMacOSXSupport.h rename to audio/mac/CDXMacOSXSupport.h diff --git a/CocosDenshion/mac/CDXMacOSXSupport.mm b/audio/mac/CDXMacOSXSupport.mm similarity index 100% rename from CocosDenshion/mac/CDXMacOSXSupport.mm rename to audio/mac/CDXMacOSXSupport.mm diff --git a/CocosDenshion/mac/CocosDenshion.h b/audio/mac/CocosDenshion.h similarity index 100% rename from CocosDenshion/mac/CocosDenshion.h rename to audio/mac/CocosDenshion.h diff --git a/CocosDenshion/mac/CocosDenshion.m b/audio/mac/CocosDenshion.m similarity index 100% rename from CocosDenshion/mac/CocosDenshion.m rename to audio/mac/CocosDenshion.m diff --git a/CocosDenshion/mac/SimpleAudioEngine.mm b/audio/mac/SimpleAudioEngine.mm similarity index 100% rename from CocosDenshion/mac/SimpleAudioEngine.mm rename to audio/mac/SimpleAudioEngine.mm diff --git a/CocosDenshion/mac/SimpleAudioEngine_objc.h b/audio/mac/SimpleAudioEngine_objc.h similarity index 100% rename from CocosDenshion/mac/SimpleAudioEngine_objc.h rename to audio/mac/SimpleAudioEngine_objc.h diff --git a/CocosDenshion/mac/SimpleAudioEngine_objc.m b/audio/mac/SimpleAudioEngine_objc.m similarity index 100% rename from CocosDenshion/mac/SimpleAudioEngine_objc.m rename to audio/mac/SimpleAudioEngine_objc.m diff --git a/CocosDenshion/openal/OpenALDecoder.cpp b/audio/openal/OpenALDecoder.cpp similarity index 100% rename from CocosDenshion/openal/OpenALDecoder.cpp rename to audio/openal/OpenALDecoder.cpp diff --git a/CocosDenshion/openal/OpenALDecoder.h b/audio/openal/OpenALDecoder.h similarity index 100% rename from CocosDenshion/openal/OpenALDecoder.h rename to audio/openal/OpenALDecoder.h diff --git a/CocosDenshion/openal/SimpleAudioEngineOpenAL.cpp b/audio/openal/SimpleAudioEngineOpenAL.cpp similarity index 100% rename from CocosDenshion/openal/SimpleAudioEngineOpenAL.cpp rename to audio/openal/SimpleAudioEngineOpenAL.cpp diff --git a/CocosDenshion/proj.emscripten/Makefile b/audio/proj.emscripten/Makefile similarity index 100% rename from CocosDenshion/proj.emscripten/Makefile rename to audio/proj.emscripten/Makefile diff --git a/CocosDenshion/proj.ios/CocosDenshion.xcodeproj/project.pbxproj b/audio/proj.ios/CocosDenshion.xcodeproj/project.pbxproj similarity index 100% rename from CocosDenshion/proj.ios/CocosDenshion.xcodeproj/project.pbxproj rename to audio/proj.ios/CocosDenshion.xcodeproj/project.pbxproj diff --git a/CocosDenshion/proj.linux/.cproject b/audio/proj.linux/.cproject similarity index 100% rename from CocosDenshion/proj.linux/.cproject rename to audio/proj.linux/.cproject diff --git a/CocosDenshion/proj.linux/.project b/audio/proj.linux/.project similarity index 100% rename from CocosDenshion/proj.linux/.project rename to audio/proj.linux/.project diff --git a/CocosDenshion/proj.linux/CocosDenshion.prf b/audio/proj.linux/CocosDenshion.prf similarity index 100% rename from CocosDenshion/proj.linux/CocosDenshion.prf rename to audio/proj.linux/CocosDenshion.prf diff --git a/CocosDenshion/proj.linux/Makefile b/audio/proj.linux/Makefile similarity index 100% rename from CocosDenshion/proj.linux/Makefile rename to audio/proj.linux/Makefile diff --git a/CocosDenshion/proj.mac/CocosDenshion.xcodeproj/project.pbxproj b/audio/proj.mac/CocosDenshion.xcodeproj/project.pbxproj similarity index 100% rename from CocosDenshion/proj.mac/CocosDenshion.xcodeproj/project.pbxproj rename to audio/proj.mac/CocosDenshion.xcodeproj/project.pbxproj diff --git a/CocosDenshion/proj.nacl/Makefile b/audio/proj.nacl/Makefile similarity index 100% rename from CocosDenshion/proj.nacl/Makefile rename to audio/proj.nacl/Makefile diff --git a/CocosDenshion/proj.qt5/cocosdenshion.pro b/audio/proj.qt5/cocosdenshion.pro similarity index 100% rename from CocosDenshion/proj.qt5/cocosdenshion.pro rename to audio/proj.qt5/cocosdenshion.pro diff --git a/CocosDenshion/proj.tizen/.cproject b/audio/proj.tizen/.cproject similarity index 100% rename from CocosDenshion/proj.tizen/.cproject rename to audio/proj.tizen/.cproject diff --git a/CocosDenshion/proj.tizen/.project b/audio/proj.tizen/.project similarity index 100% rename from CocosDenshion/proj.tizen/.project rename to audio/proj.tizen/.project diff --git a/CocosDenshion/proj.tizen/src/placeholder.txt b/audio/proj.tizen/src/placeholder.txt similarity index 100% rename from CocosDenshion/proj.tizen/src/placeholder.txt rename to audio/proj.tizen/src/placeholder.txt diff --git a/CocosDenshion/proj.win32/CocosDenshion.vcxproj b/audio/proj.win32/CocosDenshion.vcxproj similarity index 100% rename from CocosDenshion/proj.win32/CocosDenshion.vcxproj rename to audio/proj.win32/CocosDenshion.vcxproj diff --git a/CocosDenshion/proj.win32/CocosDenshion.vcxproj.filters b/audio/proj.win32/CocosDenshion.vcxproj.filters similarity index 100% rename from CocosDenshion/proj.win32/CocosDenshion.vcxproj.filters rename to audio/proj.win32/CocosDenshion.vcxproj.filters diff --git a/CocosDenshion/proj.win32/CocosDenshion.vcxproj.user b/audio/proj.win32/CocosDenshion.vcxproj.user similarity index 100% rename from CocosDenshion/proj.win32/CocosDenshion.vcxproj.user rename to audio/proj.win32/CocosDenshion.vcxproj.user diff --git a/CocosDenshion/qt5/SimpleAudioEngineQt5.cpp b/audio/qt5/SimpleAudioEngineQt5.cpp similarity index 100% rename from CocosDenshion/qt5/SimpleAudioEngineQt5.cpp rename to audio/qt5/SimpleAudioEngineQt5.cpp diff --git a/CocosDenshion/third_party/fmod/Makefile b/audio/third_party/fmod/Makefile similarity index 100% rename from CocosDenshion/third_party/fmod/Makefile rename to audio/third_party/fmod/Makefile diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod.h.REMOVED.git-id b/audio/third_party/fmod/api/inc/fmod.h.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod.h.REMOVED.git-id rename to audio/third_party/fmod/api/inc/fmod.h.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod.hpp b/audio/third_party/fmod/api/inc/fmod.hpp similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod.hpp rename to audio/third_party/fmod/api/inc/fmod.hpp diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod_codec.h b/audio/third_party/fmod/api/inc/fmod_codec.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod_codec.h rename to audio/third_party/fmod/api/inc/fmod_codec.h diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod_dsp.h b/audio/third_party/fmod/api/inc/fmod_dsp.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod_dsp.h rename to audio/third_party/fmod/api/inc/fmod_dsp.h diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod_errors.h b/audio/third_party/fmod/api/inc/fmod_errors.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod_errors.h rename to audio/third_party/fmod/api/inc/fmod_errors.h diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod_memoryinfo.h b/audio/third_party/fmod/api/inc/fmod_memoryinfo.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod_memoryinfo.h rename to audio/third_party/fmod/api/inc/fmod_memoryinfo.h diff --git a/CocosDenshion/third_party/fmod/api/inc/fmod_output.h b/audio/third_party/fmod/api/inc/fmod_output.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmod_output.h rename to audio/third_party/fmod/api/inc/fmod_output.h diff --git a/CocosDenshion/third_party/fmod/api/inc/fmodlinux.h b/audio/third_party/fmod/api/inc/fmodlinux.h similarity index 100% rename from CocosDenshion/third_party/fmod/api/inc/fmodlinux.h rename to audio/third_party/fmod/api/inc/fmodlinux.h diff --git a/CocosDenshion/third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id b/audio/third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id rename to audio/third_party/fmod/api/lib/libfmodex-4.36.01.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id b/audio/third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id rename to audio/third_party/fmod/api/lib/libfmodex.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id b/audio/third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id rename to audio/third_party/fmod/api/lib/libfmodexL-4.36.01.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id b/audio/third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id rename to audio/third_party/fmod/api/lib/libfmodexL.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/lib64/Makefile b/audio/third_party/fmod/lib64/Makefile similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/Makefile rename to audio/third_party/fmod/lib64/Makefile diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id b/audio/third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id rename to audio/third_party/fmod/lib64/api/inc/fmod.h.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod.hpp b/audio/third_party/fmod/lib64/api/inc/fmod.hpp similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod.hpp rename to audio/third_party/fmod/lib64/api/inc/fmod.hpp diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod_codec.h b/audio/third_party/fmod/lib64/api/inc/fmod_codec.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod_codec.h rename to audio/third_party/fmod/lib64/api/inc/fmod_codec.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod_dsp.h b/audio/third_party/fmod/lib64/api/inc/fmod_dsp.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod_dsp.h rename to audio/third_party/fmod/lib64/api/inc/fmod_dsp.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod_errors.h b/audio/third_party/fmod/lib64/api/inc/fmod_errors.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod_errors.h rename to audio/third_party/fmod/lib64/api/inc/fmod_errors.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod_memoryinfo.h b/audio/third_party/fmod/lib64/api/inc/fmod_memoryinfo.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod_memoryinfo.h rename to audio/third_party/fmod/lib64/api/inc/fmod_memoryinfo.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmod_output.h b/audio/third_party/fmod/lib64/api/inc/fmod_output.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmod_output.h rename to audio/third_party/fmod/lib64/api/inc/fmod_output.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/inc/fmodlinux.h b/audio/third_party/fmod/lib64/api/inc/fmodlinux.h similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/inc/fmodlinux.h rename to audio/third_party/fmod/lib64/api/inc/fmodlinux.h diff --git a/CocosDenshion/third_party/fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id b/audio/third_party/fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id rename to audio/third_party/fmod/lib64/api/lib/libfmodex64-4.38.00.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id b/audio/third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id rename to audio/third_party/fmod/lib64/api/lib/libfmodex64.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id b/audio/third_party/fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id rename to audio/third_party/fmod/lib64/api/lib/libfmodexL64-4.38.00.so.REMOVED.git-id diff --git a/CocosDenshion/third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id b/audio/third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id similarity index 100% rename from CocosDenshion/third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id rename to audio/third_party/fmod/lib64/api/lib/libfmodexL64.so.REMOVED.git-id diff --git a/CocosDenshion/win32/MciPlayer.cpp b/audio/win32/MciPlayer.cpp similarity index 100% rename from CocosDenshion/win32/MciPlayer.cpp rename to audio/win32/MciPlayer.cpp diff --git a/CocosDenshion/win32/MciPlayer.h b/audio/win32/MciPlayer.h similarity index 100% rename from CocosDenshion/win32/MciPlayer.h rename to audio/win32/MciPlayer.h diff --git a/CocosDenshion/win32/SimpleAudioEngine.cpp b/audio/win32/SimpleAudioEngine.cpp similarity index 100% rename from CocosDenshion/win32/SimpleAudioEngine.cpp rename to audio/win32/SimpleAudioEngine.cpp From fa51236dee89e5ac40b7e7a5cde7ad0019a70bdc Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 10 Oct 2013 14:40:30 +0800 Subject: [PATCH 044/116] Update CHANGELOG[ci skip] --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b9641d1f71..33a5c74148 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,13 +8,14 @@ cocos2d-x-3.0alpha1 @??? 2013 [Android] [FIX] Added EGL_RENDERABLE_TYPE to OpenGL attributes [NEW] Added Cocos2dxHelper.runOnGLThread(Runnable) again + [FIX] Fixed application will crash when pause and resume. [Mac] [FIX] Removed unused CCLOG() from GL initialization [Javascript binding] [FIX] Fixed a memory leak in ScriptingCore::runScript() [FIX] sys.localStorage.getItem() does not support non-ascii string. [Lua Binding] - [FIX] Added Armature lua binding and added test samples. + [NEW] Added Armature lua binding and added test samples. cocos2d-x-3.0alpha0 @Sep.19 2013 [all platforms] From 56c945efe62af88680941d1670986979c8390aa2 Mon Sep 17 00:00:00 2001 From: CocosRobot Date: Thu, 10 Oct 2013 06:43:01 +0000 Subject: [PATCH 045/116] [AUTO] : updating submodule reference to latest autogenerated bindings --- scripting/auto-generated | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/auto-generated b/scripting/auto-generated index ec90d1c35d..6f5bc7bbd0 160000 --- a/scripting/auto-generated +++ b/scripting/auto-generated @@ -1 +1 @@ -Subproject commit ec90d1c35d06c1de3cb5079f885c22c45b8f129b +Subproject commit 6f5bc7bbd036c76e7c6be121573662099997a0a4 From 866906fd58f581363754d73ddbcadad95809a430 Mon Sep 17 00:00:00 2001 From: minggo Date: Thu, 10 Oct 2013 15:40:06 +0800 Subject: [PATCH 046/116] issue #2905:modify project settings to include correct audio path --- Makefile | 4 ++-- cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id | 2 +- extensions/Android.mk | 2 +- samples/Cpp/AssetsManagerTest/proj.android/jni/Android.mk | 2 +- samples/Cpp/HelloCpp/proj.android/jni/Android.mk | 2 +- samples/Cpp/SimpleGame/proj.android/jni/Android.mk | 2 +- samples/Cpp/TestCpp/Android.mk | 2 +- samples/Cpp/TestCpp/proj.android/jni/Android.mk | 2 +- samples/Javascript/CocosDragonJS/proj.android/jni/Android.mk | 2 +- samples/Javascript/CrystalCraze/proj.android/jni/Android.mk | 2 +- samples/Javascript/MoonWarriors/proj.android/jni/Android.mk | 2 +- samples/Javascript/TestJavascript/proj.android/jni/Android.mk | 2 +- .../Javascript/WatermelonWithMe/proj.android/jni/Android.mk | 2 +- samples/Lua/HelloLua/proj.android/jni/Android.mk | 2 +- samples/Lua/TestLua/proj.android/jni/Android.mk | 2 +- samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id | 2 +- template/multi-platform-cpp/proj.android/jni/Android.mk | 2 +- .../proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj | 4 ++-- template/multi-platform-js/proj.android/jni/Android.mk | 2 +- .../proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj | 4 ++-- template/multi-platform-lua/proj.android/jni/Android.mk | 2 +- .../proj.ios_mac/HelloLua.xcodeproj/project.pbxproj | 4 ++-- 22 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index d82b65ec0f..fbea65f3cd 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,9 @@ libcocos2dx-clean: $(MAKE) -C cocos2dx/proj.$(PLATFORM) clean cocosdenshion: libcocos2dx - $(MAKE) -C CocosDenshion/proj.$(PLATFORM) + $(MAKE) -C audio/proj.$(PLATFORM) cocosdenshion-clean: - $(MAKE) -C CocosDenshion/proj.$(PLATFORM) clean + $(MAKE) -C audio/proj.$(PLATFORM) clean lua: libextensions $(MAKE) -C scripting/lua/proj.$(PLATFORM) diff --git a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index 48555d6a5d..367fc01cf7 100644 --- a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -3959af89b6bbc8fb982769d22d2591991107d6e5 \ No newline at end of file +dd4a9b3e507a99df58e814b627efd3983fed2eb9 \ No newline at end of file diff --git a/extensions/Android.mk b/extensions/Android.mk index 4289775bc8..8c0b1e2591 100644 --- a/extensions/Android.mk +++ b/extensions/Android.mk @@ -161,7 +161,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \ include $(BUILD_STATIC_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) $(call import-module,external/Box2D) $(call import-module,external/chipmunk) diff --git a/samples/Cpp/AssetsManagerTest/proj.android/jni/Android.mk b/samples/Cpp/AssetsManagerTest/proj.android/jni/Android.mk index a85ad02ade..42c47b9f80 100644 --- a/samples/Cpp/AssetsManagerTest/proj.android/jni/Android.mk +++ b/samples/Cpp/AssetsManagerTest/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Cpp/HelloCpp/proj.android/jni/Android.mk b/samples/Cpp/HelloCpp/proj.android/jni/Android.mk index 13989f3cf1..6ffd7d62ef 100644 --- a/samples/Cpp/HelloCpp/proj.android/jni/Android.mk +++ b/samples/Cpp/HelloCpp/proj.android/jni/Android.mk @@ -17,5 +17,5 @@ LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocos2dxandroid_static cocosdens include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Cpp/SimpleGame/proj.android/jni/Android.mk b/samples/Cpp/SimpleGame/proj.android/jni/Android.mk index e3f5b5c1ef..d0fd9a4eb2 100644 --- a/samples/Cpp/SimpleGame/proj.android/jni/Android.mk +++ b/samples/Cpp/SimpleGame/proj.android/jni/Android.mk @@ -17,7 +17,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocos2dxandroid_static cocosdens include $(BUILD_SHARED_LIBRARY) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,cocos2dx) $(call import-module,extensions) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Cpp/TestCpp/Android.mk b/samples/Cpp/TestCpp/Android.mk index 87d662be3a..ff687de48a 100644 --- a/samples/Cpp/TestCpp/Android.mk +++ b/samples/Cpp/TestCpp/Android.mk @@ -151,7 +151,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) include $(BUILD_STATIC_LIBRARY) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,external/Box2D) $(call import-module,external/chipmunk) $(call import-module,cocos2dx) diff --git a/samples/Cpp/TestCpp/proj.android/jni/Android.mk b/samples/Cpp/TestCpp/proj.android/jni/Android.mk index 98de0c8956..d72618a488 100644 --- a/samples/Cpp/TestCpp/proj.android/jni/Android.mk +++ b/samples/Cpp/TestCpp/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ include $(BUILD_SHARED_LIBRARY) $(call import-module,samples/Cpp/TestCpp) $(call import-module,cocos2dx) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,extensions) $(call import-module,external/Box2D) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Javascript/CocosDragonJS/proj.android/jni/Android.mk b/samples/Javascript/CocosDragonJS/proj.android/jni/Android.mk index 0ab251941c..bc55bdaaf5 100644 --- a/samples/Javascript/CocosDragonJS/proj.android/jni/Android.mk +++ b/samples/Javascript/CocosDragonJS/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Javascript/CrystalCraze/proj.android/jni/Android.mk b/samples/Javascript/CrystalCraze/proj.android/jni/Android.mk index 12575cad7a..451b250c37 100644 --- a/samples/Javascript/CrystalCraze/proj.android/jni/Android.mk +++ b/samples/Javascript/CrystalCraze/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Javascript/MoonWarriors/proj.android/jni/Android.mk b/samples/Javascript/MoonWarriors/proj.android/jni/Android.mk index 1cdcb62cd6..8f89f72ceb 100644 --- a/samples/Javascript/MoonWarriors/proj.android/jni/Android.mk +++ b/samples/Javascript/MoonWarriors/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Javascript/TestJavascript/proj.android/jni/Android.mk b/samples/Javascript/TestJavascript/proj.android/jni/Android.mk index 88ce0ac197..5655c291c2 100644 --- a/samples/Javascript/TestJavascript/proj.android/jni/Android.mk +++ b/samples/Javascript/TestJavascript/proj.android/jni/Android.mk @@ -23,7 +23,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,extensions) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) diff --git a/samples/Javascript/WatermelonWithMe/proj.android/jni/Android.mk b/samples/Javascript/WatermelonWithMe/proj.android/jni/Android.mk index 76b8e7fd1e..fd7d49998d 100644 --- a/samples/Javascript/WatermelonWithMe/proj.android/jni/Android.mk +++ b/samples/Javascript/WatermelonWithMe/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Lua/HelloLua/proj.android/jni/Android.mk b/samples/Lua/HelloLua/proj.android/jni/Android.mk index 54e142b5d8..e4aa117413 100644 --- a/samples/Lua/HelloLua/proj.android/jni/Android.mk +++ b/samples/Lua/HelloLua/proj.android/jni/Android.mk @@ -20,7 +20,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dxandroid_static include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/lua/proj.android) $(call import-module,extensions) $(call import-module,cocos2dx/platform/android) diff --git a/samples/Lua/TestLua/proj.android/jni/Android.mk b/samples/Lua/TestLua/proj.android/jni/Android.mk index 189dd81468..6f3a99a518 100644 --- a/samples/Lua/TestLua/proj.android/jni/Android.mk +++ b/samples/Lua/TestLua/proj.android/jni/Android.mk @@ -24,7 +24,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dxandroid_static include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/lua/proj.android) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) $(call import-module,extensions) diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index ec33bf839a..bc96bbb791 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -381c282bed409f4b41a82505460d4d6c84ba70ab \ No newline at end of file +609e133ab0e4ace89f5ddf8710506b08ff2e952b \ No newline at end of file diff --git a/template/multi-platform-cpp/proj.android/jni/Android.mk b/template/multi-platform-cpp/proj.android/jni/Android.mk index 5430a288ba..97616f1fba 100644 --- a/template/multi-platform-cpp/proj.android/jni/Android.mk +++ b/template/multi-platform-cpp/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,extensions) $(call import-module,external/Box2D) $(call import-module,cocos2dx/platform/android) diff --git a/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj b/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj index 3cb7edab03..3f7b3750a3 100644 --- a/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj +++ b/template/multi-platform-cpp/proj.ios_mac/HelloCpp.xcodeproj/project.pbxproj @@ -821,7 +821,7 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../CocosDenshion/include", + "$(SRCROOT)/../../../audio/include", "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", "\"$(SRCROOT)/../../../extensions\"", @@ -861,7 +861,7 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../CocosDenshion/include", + "$(SRCROOT)/../../../audio/include", "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", "\"$(SRCROOT)/../../../extensions\"", diff --git a/template/multi-platform-js/proj.android/jni/Android.mk b/template/multi-platform-js/proj.android/jni/Android.mk index 09cabaea59..3b09a62b57 100644 --- a/template/multi-platform-js/proj.android/jni/Android.mk +++ b/template/multi-platform-js/proj.android/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_EXPORT_CFLAGS := -DCOCOS2D_DEBUG=2 -DCOCOS2D_JAVASCRIPT include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/javascript/spidermonkey-android) $(call import-module,scripting/javascript/bindings) $(call import-module,cocos2dx/platform/android) diff --git a/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj b/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj index 9958c7a786..dbc340d66f 100644 --- a/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj +++ b/template/multi-platform-js/proj.ios_mac/HelloJavascript.xcodeproj/project.pbxproj @@ -923,7 +923,7 @@ "\"$(SRCROOT)/../../../cocos2dx\"", "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", "$(SRCROOT)/../../../cocos2dx/platform/third_party/ios", - "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../audio/include\"", "$(SRCROOT)/../../../cocos2dx/include", "$(SRCROOT)/../../../cocos2dx/platform/ios", "$(SRCROOT)/../../../external/chipmunk/include/chipmunk", @@ -965,7 +965,7 @@ "\"$(SRCROOT)/../../../cocos2dx\"", "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", "$(SRCROOT)/../../../cocos2dx/platform/third_party/ios", - "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../audio/include\"", "$(SRCROOT)/../../../cocos2dx/include", "$(SRCROOT)/../../../cocos2dx/platform/ios", "$(SRCROOT)/../../../external/chipmunk/include/chipmunk", diff --git a/template/multi-platform-lua/proj.android/jni/Android.mk b/template/multi-platform-lua/proj.android/jni/Android.mk index 05362699b5..af986970fe 100644 --- a/template/multi-platform-lua/proj.android/jni/Android.mk +++ b/template/multi-platform-lua/proj.android/jni/Android.mk @@ -25,7 +25,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dxandroid_static include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx) -$(call import-module,CocosDenshion/android) +$(call import-module,audio/android) $(call import-module,scripting/lua/proj.android) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) $(call import-module,extensions) diff --git a/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj b/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj index 8403e89e8a..67d6e16713 100644 --- a/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj +++ b/template/multi-platform-lua/proj.ios_mac/HelloLua.xcodeproj/project.pbxproj @@ -992,7 +992,7 @@ "\"$(SRCROOT)/../../../scripting/lua/cocos2dx_support\"", "\"$(SRCROOT)/../../../cocos2dx/platform/ios\"", "\"$(SRCROOT)/../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../audio/include\"", "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", "\"$(SRCROOT)/../../../external\"", @@ -1035,7 +1035,7 @@ "\"$(SRCROOT)/../../../scripting/lua/cocos2dx_support\"", "\"$(SRCROOT)/../../../cocos2dx/platform/ios\"", "\"$(SRCROOT)/../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../audio/include\"", "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", "\"$(SRCROOT)/../../../external\"", From 2e07b0736b073ff90f985846d9bccf68e4fde101 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 10 Oct 2013 16:13:37 +0800 Subject: [PATCH 047/116] Update .gitmodules, fix wrong reference of auto-generated. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index eb0c7b5ec4..f7313b3346 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "tools/bindings-generator"] path = tools/bindings-generator url = git://github.com/cocos2d/bindings-generator.git -[submodule "scripting/javascript/bindings/generated"] +[submodule "scripting/auto-generated"] path = scripting/auto-generated url = git://github.com/folecr/cocos2dx-autogen-bindings.git [submodule "samples/Javascript/Shared"] From c381e4ce50f1f83876680c8fb4b090645d6cfb3c Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 5 Oct 2013 10:56:52 +0800 Subject: [PATCH 048/116] issue #2823: firefox remote connection ok. --- .../javascript/bindings/ScriptingCore.cpp | 177 ++++++++++++++++-- .../javascript/bindings/js_bindings_config.h | 2 +- 2 files changed, 167 insertions(+), 12 deletions(-) diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index 33fd2aee1f..fc21464922 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -1938,7 +1938,8 @@ void ScriptingCore::enableDebugger() { JS_DefineFunction(cx_, debugGlobal_, "_unlockVM", JSBDebug_UnlockExecution, 0, JSPROP_READONLY | JSPROP_PERMANENT); runScript("jsb_debugger.js", debugGlobal_); - + runScript("SysTest/script.js", debugGlobal_); + // prepare the debugger jsval argv = OBJECT_TO_JSVAL(global_); jsval outval; @@ -2166,6 +2167,13 @@ static void clearBuffers() { } } +static int replyToClient(int socket, const std::string& buf) +{ + std::stringstream bufSend; + bufSend << buf.length() << ":" << buf; + return ::send(socket, bufSend.str().c_str(), bufSend.str().length(), 0); +} + static void serverEntryPoint(void) { // start a server, accept the connection and keep reading data from it @@ -2218,25 +2226,172 @@ static void serverEntryPoint(void) listen(s, 1); + int recieveIndex = 0; while (true) { clientSocket = accept(s, NULL, NULL); + if (clientSocket < 0) - { - TRACE_DEBUGGER_SERVER("debug server : error on accept"); - return; - } else { + { + TRACE_DEBUGGER_SERVER("debug server : error on accept"); + return; + } + else + { // read/write data TRACE_DEBUGGER_SERVER("debug server : client connected"); - char buf[256]; - int readBytes; - while ((readBytes = read(clientSocket, buf, 256)) > 0) { + + if (recieveIndex == 0) + { + replyToClient(clientSocket, "{\"from\":\"root\",\"applicationType\":\"browser\",\"traits\":{\"sources\": true}}"); + ++recieveIndex; + } + + + char buf[256] = {0}; + int readBytes = 0; + while ((readBytes = ::recv(clientSocket, buf, sizeof(buf), 0)) > 0) + { buf[readBytes] = '\0'; TRACE_DEBUGGER_SERVER("debug server : received command >%s", buf); + + if (recieveIndex == 1) + { + replyToClient(clientSocket, "{ \"from\":\"root\", \"tabs\":[{ \"actor\":\"JSBTabActor\", \"title\":\"Hello cocos2d-x JSB\", \"url\":\"http://www.cocos2d-x.org\" }], \"selected\":0 }"); + } + else if (recieveIndex == 2) + { + replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabAttached\", \"threadActor\":\"tabThreadActor111\" }"); + } + else if (recieveIndex == 3) + { + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"paused\",\ + \"actor\": \"JSBTabActor\",\ + \"poppedFrames\": [],\ + \"why\": {\ + \"type\": \"attached\"\ + }\ + }"); + + + + //replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabNavigated\", \"state\":\"start\", \"url\":\"my_url.js\" }"); + } + else if (recieveIndex == 4) + { +// replyToClient(clientSocket, "{\"from\": \"tabThreadActor111\",\ +// \"type\": \"newSource\",\ +// \"source\": {\ +// \"actor\": \"source_actor2\",\ +// \"url\": \"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js\",\ +// \"isBlackBoxed\": false\ +// }}"); + + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"newSource\",\ + \"source\": {\ + \"actor\": \"source_actor1\",\ + \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ + \"isBlackBoxed\": false\ + }\ + }"); + + replyToClient(clientSocket, + "{\ + \"sources\": [\ + {\ + \"actor\": \"source_actor1\",\ + \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ + \"isBlackBoxed\": false\ + }\ + ],\ + \"from\": \"tabThreadActor111\"\ + }"); + } + else if (recieveIndex == 5) + { + replyToClient(clientSocket, "{\ + \"from\": \"source_actor1\",\ + \"source\": {\ + \"type\": \"longString\",\ + \"initial\": \"var cc = cc || {}; cc.Director = {};\",\ + \"length\": 100,\ + \"actor\": \"conn2.longString48\"\ + }\ + }"); + } + else if (recieveIndex == 6) + { + replyToClient(clientSocket, "{\ + \"from\": \"conn2.longString48\",\ + \"substring\": \"var cc = cc || {}; cc.Director = {};\ +\\ncc.Sprite = {};\"\ + }"); + + + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"resumed\"\ + }"); + } + else if (recieveIndex == 7) + { + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"resumed\"\ + }"); + } + else if (recieveIndex == 8) + { + replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); + } + else if (recieveIndex == 9) + { + replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); + } + else if (recieveIndex == 10) + { + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"resumed\"\ + }"); + } + else + { + + + std::string recvBuf = buf; + auto found = recvBuf.find("setBreakpoint"); + if (found != std::string::npos) + { + replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); + } + + found = recvBuf.find("delete"); + if (found != std::string::npos) + { + replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); + } + + found = recvBuf.find("interrupt"); + if (found != std::string::npos) + { + replyToClient(clientSocket, "{\ + \"from\": \"tabThreadActor111\",\ + \"type\": \"resumed\"\ + }"); + } + + } + ++recieveIndex; // no other thread is using this - inData.append(buf); - // process any input, send any output - clearBuffers(); +// inData.append(buf); +// // process any input, send any output +// clearBuffers(); } // while(read) + close(clientSocket); } } // while(true) diff --git a/scripting/javascript/bindings/js_bindings_config.h b/scripting/javascript/bindings/js_bindings_config.h index 2216f2fca2..bfe1d64f96 100644 --- a/scripting/javascript/bindings/js_bindings_config.h +++ b/scripting/javascript/bindings/js_bindings_config.h @@ -141,7 +141,7 @@ Set this to 1 to enable the debugger */ #ifndef JSB_ENABLE_DEBUGGER -#define JSB_ENABLE_DEBUGGER 0 +#define JSB_ENABLE_DEBUGGER 1 #endif // JSB_ENABLE_DEBUGGER #if JSB_ENABLE_DEBUGGER From d033411bbe7946ba601ec43b6053673c60a113b5 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 5 Oct 2013 11:24:25 +0800 Subject: [PATCH 049/116] issue #2823: comment some test codes. --- .../javascript/bindings/ScriptingCore.cpp | 258 +++++++++--------- 1 file changed, 125 insertions(+), 133 deletions(-) diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index fc21464922..77ba232fc0 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -1938,7 +1938,7 @@ void ScriptingCore::enableDebugger() { JS_DefineFunction(cx_, debugGlobal_, "_unlockVM", JSBDebug_UnlockExecution, 0, JSPROP_READONLY | JSPROP_PERMANENT); runScript("jsb_debugger.js", debugGlobal_); - runScript("SysTest/script.js", debugGlobal_); +// runScript("SysTest/script.js", debugGlobal_); // prepare the debugger jsval argv = OBJECT_TO_JSVAL(global_); @@ -2254,142 +2254,134 @@ static void serverEntryPoint(void) buf[readBytes] = '\0'; TRACE_DEBUGGER_SERVER("debug server : received command >%s", buf); - if (recieveIndex == 1) - { - replyToClient(clientSocket, "{ \"from\":\"root\", \"tabs\":[{ \"actor\":\"JSBTabActor\", \"title\":\"Hello cocos2d-x JSB\", \"url\":\"http://www.cocos2d-x.org\" }], \"selected\":0 }"); - } - else if (recieveIndex == 2) - { - replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabAttached\", \"threadActor\":\"tabThreadActor111\" }"); - } - else if (recieveIndex == 3) - { - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"paused\",\ - \"actor\": \"JSBTabActor\",\ - \"poppedFrames\": [],\ - \"why\": {\ - \"type\": \"attached\"\ - }\ - }"); - - - - //replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabNavigated\", \"state\":\"start\", \"url\":\"my_url.js\" }"); - } - else if (recieveIndex == 4) - { -// replyToClient(clientSocket, "{\"from\": \"tabThreadActor111\",\ +// if (recieveIndex == 1) +// { +// replyToClient(clientSocket, "{ \"from\":\"root\", \"tabs\":[{ \"actor\":\"JSBTabActor\", \"title\":\"Hello cocos2d-x JSB\", \"url\":\"http://www.cocos2d-x.org\" }], \"selected\":0 }"); +// } +// else if (recieveIndex == 2) +// { +// replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabAttached\", \"threadActor\":\"tabThreadActor111\" }"); +// } +// else if (recieveIndex == 3) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ +// \"type\": \"paused\",\ +// \"actor\": \"JSBTabActor\",\ +// \"poppedFrames\": [],\ +// \"why\": {\ +// \"type\": \"attached\"\ +// }\ +// }"); +// +// +// +// //replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabNavigated\", \"state\":\"start\", \"url\":\"my_url.js\" }"); +// } +// else if (recieveIndex == 4) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ // \"type\": \"newSource\",\ // \"source\": {\ -// \"actor\": \"source_actor2\",\ -// \"url\": \"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js\",\ +// \"actor\": \"source_actor1\",\ +// \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ // \"isBlackBoxed\": false\ -// }}"); - - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"newSource\",\ - \"source\": {\ - \"actor\": \"source_actor1\",\ - \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ - \"isBlackBoxed\": false\ - }\ - }"); - - replyToClient(clientSocket, - "{\ - \"sources\": [\ - {\ - \"actor\": \"source_actor1\",\ - \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ - \"isBlackBoxed\": false\ - }\ - ],\ - \"from\": \"tabThreadActor111\"\ - }"); - } - else if (recieveIndex == 5) - { - replyToClient(clientSocket, "{\ - \"from\": \"source_actor1\",\ - \"source\": {\ - \"type\": \"longString\",\ - \"initial\": \"var cc = cc || {}; cc.Director = {};\",\ - \"length\": 100,\ - \"actor\": \"conn2.longString48\"\ - }\ - }"); - } - else if (recieveIndex == 6) - { - replyToClient(clientSocket, "{\ - \"from\": \"conn2.longString48\",\ - \"substring\": \"var cc = cc || {}; cc.Director = {};\ -\\ncc.Sprite = {};\"\ - }"); - - - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"resumed\"\ - }"); - } - else if (recieveIndex == 7) - { - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"resumed\"\ - }"); - } - else if (recieveIndex == 8) - { - replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); - } - else if (recieveIndex == 9) - { - replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); - } - else if (recieveIndex == 10) - { - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"resumed\"\ - }"); - } - else - { - - - std::string recvBuf = buf; - auto found = recvBuf.find("setBreakpoint"); - if (found != std::string::npos) - { - replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); - } - - found = recvBuf.find("delete"); - if (found != std::string::npos) - { - replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); - } - - found = recvBuf.find("interrupt"); - if (found != std::string::npos) - { - replyToClient(clientSocket, "{\ - \"from\": \"tabThreadActor111\",\ - \"type\": \"resumed\"\ - }"); - } - - } - ++recieveIndex; +// }\ +// }"); +// +// replyToClient(clientSocket, +// "{\ +// \"sources\": [\ +// {\ +// \"actor\": \"source_actor1\",\ +// \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ +// \"isBlackBoxed\": false\ +// }\ +// ],\ +// \"from\": \"tabThreadActor111\"\ +// }"); +// } +// else if (recieveIndex == 5) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"source_actor1\",\ +// \"source\": {\ +// \"type\": \"longString\",\ +// \"initial\": \"var cc = cc || {}; cc.Director = {};\",\ +// \"length\": 100,\ +// \"actor\": \"conn2.longString48\"\ +// }\ +// }"); +// } +// else if (recieveIndex == 6) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"conn2.longString48\",\ +// \"substring\": \"var cc = cc || {}; cc.Director = {};\ +//\\ncc.Sprite = {};\"\ +// }"); +// +// +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ +// \"type\": \"resumed\"\ +// }"); +// } +// else if (recieveIndex == 7) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ +// \"type\": \"resumed\"\ +// }"); +// } +// else if (recieveIndex == 8) +// { +// replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); +// } +// else if (recieveIndex == 9) +// { +// replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); +// } +// else if (recieveIndex == 10) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ +// \"type\": \"resumed\"\ +// }"); +// } +// else +// { +// +// +// std::string recvBuf = buf; +// auto found = recvBuf.find("setBreakpoint"); +// if (found != std::string::npos) +// { +// replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); +// } +// +// found = recvBuf.find("delete"); +// if (found != std::string::npos) +// { +// replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); +// } +// +// found = recvBuf.find("interrupt"); +// if (found != std::string::npos) +// { +// replyToClient(clientSocket, "{\ +// \"from\": \"tabThreadActor111\",\ +// \"type\": \"resumed\"\ +// }"); +// } +// +// } +// ++recieveIndex; // no other thread is using this -// inData.append(buf); -// // process any input, send any output -// clearBuffers(); + inData.append(buf); + // process any input, send any output + clearBuffers(); } // while(read) close(clientSocket); From b5679cbc3a99ee68fc4bc9cc8278e6baa2bea28c Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 7 Oct 2013 10:50:12 +0800 Subject: [PATCH 050/116] issue #2823: load js file in firefox. --- .../javascript/bindings/ScriptingCore.cpp | 92 ++-- scripting/javascript/bindings/ScriptingCore.h | 2 +- .../javascript/bindings/js/jsb_debugger.js | 408 +++++++++++++++++- 3 files changed, 466 insertions(+), 36 deletions(-) diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index 77ba232fc0..0ed5b8eb68 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -392,7 +392,6 @@ JSBool ScriptingCore::evalString(const char *string, jsval *outVal, const char * global = global_; JSScript* script = JS_CompileScript(cx, global, string, strlen(string), filename, 1); if (script) { - // JSAutoCompartment ac(cx, global); JSAutoCompartment ac(cx, global); JSBool evaluatedOK = JS_ExecuteScript(cx, global, script, outVal); if (JS_FALSE == evaluatedOK) { @@ -463,19 +462,23 @@ void ScriptingCore::createGlobalContext() { this->cx_ = JS_NewContext(rt_, 8192); JS_SetOptions(this->cx_, JSOPTION_TYPE_INFERENCE); - JS_SetVersion(this->cx_, JSVERSION_LATEST); + +// JS_SetVersion(this->cx_, JSVERSION_LATEST); // Only disable METHODJIT on iOS. -#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) - JS_SetOptions(this->cx_, JS_GetOptions(this->cx_) & ~JSOPTION_METHODJIT); - JS_SetOptions(this->cx_, JS_GetOptions(this->cx_) & ~JSOPTION_METHODJIT_ALWAYS); -#endif +//#if (CC_TARGET_PLATFORM == CC_PLATFORM_ +// JS_SetOptions(this->cx_, JS_GetOptions(this->cx_) & ~JSOPTION_METHODJIT); +// JS_SetOptions(this->cx_, JS_GetOptions(this->cx_) & ~JSOPTION_METHODJIT_ALWAYS); +//#endif JS_SetErrorReporter(this->cx_, ScriptingCore::reportError); #if defined(JS_GC_ZEAL) && defined(DEBUG) //JS_SetGCZeal(this->cx_, 2, JS_DEFAULT_ZEAL_FREQ); #endif + this->global_ = NewGlobalObject(cx_); + JSAutoCompartment ac(cx_, global_); + #if JSB_ENABLE_DEBUGGER JS_SetDebugMode(cx_, JS_TRUE); #endif @@ -500,6 +503,8 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c if (!path) { return false; } + + cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance(); std::string fullPath = futil->fullPathForFilename(path); if (global == NULL) { @@ -508,7 +513,12 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c if (cx == NULL) { cx = cx_; } - JSScript *script = NULL; + + JSAutoCompartment ac(cx, global); + + uint32_t oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); + js::RootedObject obj(cx, global); JS::CompileOptions options(cx); options.setUTF8(true).setFileAndLine(fullPath.c_str(), 1); @@ -519,6 +529,8 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c void *data = futil->getFileData(byteCodePath.c_str(), "rb", &length); + + js::RootedScript script(cx); if (data) { script = JS_DecodeScript(cx, data, length, NULL, NULL); CC_SAFE_DELETE_ARRAY(data); @@ -930,15 +942,16 @@ JSBool ScriptingCore::executeFunctionWithOwner(jsval owner, const char *name, ui do { + JSAutoCompartment ac(cx, obj); + if (JS_HasProperty(cx, obj, name, &hasAction) && hasAction) { if (!JS_GetProperty(cx, obj, name, &temp_retval)) { break; } if (temp_retval == JSVAL_VOID) { break; - } + } - JSAutoCompartment ac(cx, obj); if (retVal) { bRet = JS_CallFunctionName(cx, obj, name, argc, vp, retVal); } @@ -1099,6 +1112,8 @@ int ScriptingCore::sendEvent(ScriptEvent* evt) { if (NULL == evt) return 0; + + JSAutoCompartment ac(cx_, global_); switch (evt->type) { @@ -1199,7 +1214,7 @@ JSBool jsval_to_long_long(JSContext *cx, jsval vp, long long* r) { } JSBool jsval_to_std_string(JSContext *cx, jsval v, std::string* ret) { - JSString *tmp = v.isString() ? JS_ValueToString(cx, v) : NULL; + JSString *tmp = JS_ValueToString(cx, v); JSB_PRECONDITION3(tmp, cx, JS_FALSE, "Error processing arguments"); JSStringWrapper str(tmp); @@ -1736,14 +1751,24 @@ jsval long_long_to_jsval(JSContext* cx, long long v) { return OBJECT_TO_JSVAL(tmp); } -jsval std_string_to_jsval(JSContext* cx, const std::string& v) { - return c_string_to_jsval(cx, v.c_str()); +jsval std_string_to_jsval(JSContext* cx, const std::string& v) +{ + return c_string_to_jsval(cx, v.c_str(), v.size()); } -jsval c_string_to_jsval(JSContext* cx, const char* v, size_t length /* = -1 */) { - if (v == NULL) { +jsval c_string_to_jsval(JSContext* cx, const char* v, size_t length /* = -1 */) +{ + if (v == NULL) + { return JSVAL_NULL; } + + if (0 == length) + { + auto emptyStr = JS_NewStringCopyZ(cx, ""); + return STRING_TO_JSVAL(emptyStr); + } + jsval ret = JSVAL_NULL; int utf16_size = 0; jschar* strUTF16 = (jschar*)cc_utf8_to_utf16(v, length, &utf16_size); @@ -1914,6 +1939,8 @@ void SimpleRunLoop::update(float dt) { } void ScriptingCore::debugProcessInput(string str) { + JSAutoCompartment ac(cx_, debugGlobal_); + JSString* jsstr = JS_NewStringCopyZ(cx_, str.c_str()); jsval argv[3] = { STRING_TO_JSVAL(jsstr), @@ -1921,12 +1948,13 @@ void ScriptingCore::debugProcessInput(string str) { script }; jsval outval; - JSAutoCompartment ac(cx_, debugGlobal_); + JS_CallFunctionName(cx_, debugGlobal_, "processInput", 3, argv, &outval); } void ScriptingCore::enableDebugger() { if (debugGlobal_ == NULL) { + JSAutoCompartment ac0(cx_, global_); debugGlobal_ = NewGlobalObject(cx_, true); JS_WrapObject(cx_, &debugGlobal_); JSAutoCompartment ac(cx_, debugGlobal_); @@ -1940,6 +1968,7 @@ void ScriptingCore::enableDebugger() { runScript("jsb_debugger.js", debugGlobal_); // runScript("SysTest/script.js", debugGlobal_); + CCLOG("before _prepareDebugger..."); // prepare the debugger jsval argv = OBJECT_TO_JSVAL(global_); jsval outval; @@ -1947,6 +1976,8 @@ void ScriptingCore::enableDebugger() { if (!ok) { JS_ReportPendingException(cx_); } + + CCLOG("after _prepareDebugger..."); // define the start debugger function JS_DefineFunction(cx_, global_, "startDebugger", JSBDebug_StartDebugger, 3, JSPROP_READONLY | JSPROP_PERMANENT); // start bg thread @@ -1954,6 +1985,7 @@ void ScriptingCore::enableDebugger() { auto t = std::thread(&serverEntryPoint); t.detach(); + CCLOG("after _prepareDebugger...02"); Scheduler* scheduler = Director::getInstance()->getScheduler(); scheduler->scheduleUpdateForTarget(this->runLoop, 0, false); } @@ -1991,15 +2023,23 @@ JSBool jsGetScript(JSContext* cx, unsigned argc, jsval* vp) JSObject* NewGlobalObject(JSContext* cx, bool debug) { - JSObject* glob = JS_NewGlobalObject(cx, &global_class, NULL); - if (!glob) { + JS::CompartmentOptions options; + options.setZone(JS::FreshZone) + .setVersion(JSVERSION_LATEST); + JS::RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL, options)); + + if (!glob) + { return NULL; } + JSAutoCompartment ac(cx, glob); JSBool ok = JS_TRUE; ok = JS_InitStandardClasses(cx, glob); if (ok) - JS_InitReflect(cx, glob); + { + ok = JS_InitReflect(cx, glob) != NULL; + } if (ok && debug) ok = JS_DefineDebuggerObject(cx, glob); if (!ok) @@ -2240,14 +2280,18 @@ static void serverEntryPoint(void) // read/write data TRACE_DEBUGGER_SERVER("debug server : client connected"); - if (recieveIndex == 0) - { - replyToClient(clientSocket, "{\"from\":\"root\",\"applicationType\":\"browser\",\"traits\":{\"sources\": true}}"); - ++recieveIndex; - } + inData = "connected"; + // process any input, send any output + clearBuffers(); + +// if (recieveIndex == 0) +// { +// replyToClient(clientSocket, "{\"from\":\"root\",\"applicationType\":\"browser\",\"traits\":{\"sources\": true}}"); +// ++recieveIndex; +// } - char buf[256] = {0}; + char buf[1024] = {0}; int readBytes = 0; while ((readBytes = ::recv(clientSocket, buf, sizeof(buf), 0)) > 0) { diff --git a/scripting/javascript/bindings/ScriptingCore.h b/scripting/javascript/bindings/ScriptingCore.h index f7b8cb29e1..bea0541b82 100644 --- a/scripting/javascript/bindings/ScriptingCore.h +++ b/scripting/javascript/bindings/ScriptingCore.h @@ -192,7 +192,7 @@ public: void debugProcessInput(string str); void enableDebugger(); JSObject* getDebugGlobal() { return debugGlobal_; } - JSObject* getGlobalObject() { return global_; } + JSObject* getGlobalObject() { return global_ ? global_ : debugGlobal_; } private: void string_report(jsval val); diff --git a/scripting/javascript/bindings/js/jsb_debugger.js b/scripting/javascript/bindings/js/jsb_debugger.js index 20fecc78c2..8d701d22f6 100644 --- a/scripting/javascript/bindings/js/jsb_debugger.js +++ b/scripting/javascript/bindings/js/jsb_debugger.js @@ -1,4 +1,8 @@ -dbg = {}; +dbg = { + LONG_STRING_LENGTH: 10000, + LONG_STRING_INITIAL_LENGTH: 1000, + LONG_STRING_READ_LENGTH: 1000 +}; dbg.log = log; var textCommandProcessor = {}; @@ -299,7 +303,39 @@ jsonResponder.onBreakpoint = function (filename, linenumber) { "data" : {"jsfilename" : filename, "linenumber" : linenumber}}; - this.write(JSON.stringify(response)); + dbg.log("onBreakpoint: " + JSON.stringify(response)); + +var breakInfo = { "from":"tabThreadActor111", "type":"paused", "actor":"pauseActor", + "why":{ "type":"breakpoint", "actors":["breakpointActor1"] }, + "frame":{ "actor":"frameActor", "depth":1, + "type":"call", "where":{ "url":"sample.js", "line":3 }, + "environment":{ "type":"function", "actor":"gFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"gActor" }, + "functionName":"g", + "bindings":{ arguments: [ { "y": { "value":"argument to g", "configurable":"false", + "writable":true, "enumerable":true } } ] }, + "parent":{ "type":"function", "actor":"fFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"fActor" }, + "functionName":"f", + "bindings": { arguments: [ { "x": { "value":"argument to f", "configurable":"false", + "writable":true, "enumerable":true } } ], + variables: { "z": { "value":"value of z", "configurable":"false", + "writable":true, "enumerable":true } } }, + "parent":{ "type":"object", "actor":"globalCodeActor", + "object":{ "type":"object", "class":"Global", + "actor":"globalObjectActor" } + } + } + }, + "callee":"gActor", "calleeName":"g", + "this":{ "type":"object", "class":"Function", "actor":"gActor" }, + "arguments":["argument to g"] + } + }; + + _RDPWrite(breakInfo); + + //this.write(JSON.stringify(response)); } jsonResponder.onStep = function (filename, linenumber) { @@ -332,10 +368,45 @@ textResponder.write = function (str) { _bufferWrite(String.fromCharCode(23)); } -textResponder.onBreakpoint = function (filename, linenumber) { - var shortFilename = filename.substring(filename.lastIndexOf("/") + 1); - var response = "Breakpoint hit at " + shortFilename + " line number : " + linenumber; - this.write(response); +var breakpointFrame = null; + +textResponder.onBreakpoint = function (frame) {//filename, linenumber) { + // var shortFilename = filename.substring(filename.lastIndexOf("/") + 1); + // var response = "Breakpoint hit at " + shortFilename + " line number : " + linenumber; + // dbg.log("textResponder.onBreakpoint:"+response); + + var breakInfo = { "from":"tabThreadActor111", "type":"paused", "actor":"pauseActor", + "why":{ "type":"breakpoint", "actors":["breakpointActor1"] }, + "frame":{ "actor":"frameActor", "depth":1, + "type":"call", "where":{ "url":"sample.js", "line":3 }, + "environment":{ "type":"function", "actor":"gFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"gActor" }, + "functionName":"g", + "bindings":{ arguments: [ { "y": { "value":"argument to g", "configurable":"false", + "writable":true, "enumerable":true } } ] }, + "parent":{ "type":"function", "actor":"fFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"fActor" }, + "functionName":"f", + "bindings": { arguments: [ { "x": { "value":"argument to f", "configurable":"false", + "writable":true, "enumerable":true } } ], + variables: { "z": { "value":"value of z", "configurable":"false", + "writable":true, "enumerable":true } } }, + "parent":{ "type":"object", "actor":"globalCodeActor", + "object":{ "type":"object", "class":"Global", + "actor":"globalObjectActor" } + } + } + }, + "callee":"gActor", "calleeName":"g", + "this":{ "type":"object", "class":"Function", "actor":"gActor" }, + "arguments":["argument to g"] + } + }; + + breakpointFrame = frame; + _RDPWrite(breakInfo); + + // this.write(response); } textResponder.onStep = function (filename, linenumber) { @@ -420,8 +491,9 @@ textResponder.commandNotFound = function () { var breakpointHandler = { hit: function (frame) { + dbg.log("breakpointHandler hit"); try { - dbg.responder.onBreakpoint(frame.script.url, frame.script.getOffsetLine(frame.offset)); + dbg.responder.onBreakpoint(frame);//frame.script.url, frame.script.getOffsetLine(frame.offset)); } catch (e) { dbg.log("exception " + e); } @@ -487,6 +559,71 @@ var debugObject = function (r, isNormal) { dbg.breakLine = 0; +dbg.scriptSourceActorMap = {}; + + + +addFiles = function() { + for (var key in dbg.scripts) + { + dbg.log("sources:" + key); + var scripts = dbg.scripts[key]; + for (var i = 0; i < scripts.length; ++i) + { + dbg.log("url:" + scripts[i].source.url); + dbg.log("-----------"); + + dbg.scriptSourceActorMap[key+"_SourceActor"] = scripts[i]; + + _RDPWrite( + { + from: "tabThreadActor111", + type: "newSource", + source: { + actor: key+"_SourceActor", + url: "file://" + scripts[i].source.url, + isBlackBoxed: false + } + }); + } + } +}; + +addInitialSource = function(sourceActor, script) +{ + _RDPWrite( + { + from: sourceActor, + source: { + type: "longString", + initial: script.source.text.substring(0, dbg.LONG_STRING_INITIAL_LENGTH), + length: script.source.text.length, + actor: sourceActor+"_LongString" + } + }); +} + +addSource = function(longStringActor, script) +{ + _RDPWrite( + { + from: longStringActor, + substring: script.source.text + }); +} + +isStringStartWith = function (str, substring) { + var reg = new RegExp("^"+substring); + return reg.test(str); +}; + +isStringEndsWith = function (str, substring) { + var reg = new RegExp(substring + "$"); + return reg.test(str); +}; + +var breakpointActorIndex = 0; + this.processInput = function (inputstr, frame, script) { var command_func; var command_return; @@ -498,6 +635,240 @@ this.processInput = function (inputstr, frame, script) { return; } +// var testStr = "104:{\ +// \"to\": \"tabThreadActor111\",\ +// \"type\": \"resume\",\ +// \"resumeLimit\": null,\ +// \"pauseOnExceptions\": false\ +// }60:{\ +// \"to\": \"ActionsTest.js_SourceActor\",\ +// \"type\": \"source\"\ +// }"; + + // for (var i = 0; i < testArr.length; ++i) + // { + // dbg.log("split: " +"{"+ testArr[i] + ",length= "+testArr.length); + // } + + var inputArr = inputstr.split(/\d+:{/g); + + if (inputArr.length > 1) + { + inputArr.shift(); + for (var i = 0; i < inputArr.length; ++i) { + // dbg.log("---> "+inputArr[i]); + processInput("{"+inputArr[i], frame, script); + } + return; + } + + // dbg.log("inputStr:"+inputstr); + + if (inputstr === "connected") + { + var rootInit = {from:"root",applicationType:"browser",traits:{sources: true}}; + _RDPWrite(rootInit); + return; + } + + // var semi = inputstr.indexOf(":"); + + // if (semi === -1) + // { + // dbg.log("wrong input remote debugger protocol string."); + // return; + // } + + var jsonStr = inputstr;//.substring(semi+1); + dbg.log("jsonStr:" + jsonStr); + var jsonObj = JSON.parse(jsonStr); + // for (var key in jsonObj) + // { + // dbg.log("["+key+"]="+jsonObj[key]); + // } + + if (jsonObj.to === "root" && jsonObj.type === "listTabs") + { + _RDPWrite({ from:"root", tabs:[{ actor:"JSBTabActor", title:"Hello cocos2d-x JSB", url:"http://www.cocos2d-x.org" }], selected:0 }); + } + else if (jsonObj.to === "JSBTabActor" && jsonObj.type === "attach") + { + _RDPWrite({ from:"JSBTabActor", type:"tabAttached", threadActor:"tabThreadActor111" }); + } + else if (jsonObj.to === "tabThreadActor111" && jsonObj.type === "attach") + { + _RDPWrite( + { + from: "tabThreadActor111", + type: "paused", + actor: "JSBTabActor", + poppedFrames: [], + why: { + type: "attached" + } + }); + } + else if (jsonObj.to === "tabThreadActor111" && jsonObj.type === "sources") + { + addFiles(); + } + else if (jsonObj.to && isStringEndsWith(jsonObj.to, "_SourceActor") && jsonObj.type === "source") + { + dbg.log("require source ...: " + jsonObj.to); + var script = dbg.scriptSourceActorMap[jsonObj.to]; + + if (script) + { + addInitialSource(jsonObj.to, script); + } + } + else if (jsonObj.to && isStringEndsWith(jsonObj.to, "_LongString") && jsonObj.type === "substring") + { + var sourceActor = jsonObj.to.substring(0, jsonObj.to.length-"_LongString".length); + dbg.log("source actor: " + sourceActor); + var script = dbg.scriptSourceActorMap[sourceActor]; + + if (script) + { + addSource(jsonObj.to, script); + } + + _RDPWrite({ + from: "tabThreadActor111", + type: "resumed" + }); + } + else if (jsonObj.to === "tabThreadActor111" && jsonObj.type === "resume") + { + dbg.log("resume type to server...."); + _RDPWrite({ + from: "tabThreadActor111", + type: "resumed" + }); + } + else if (jsonObj.to === "tabThreadActor111" && jsonObj.type === "setBreakpoint") + { + ++breakpointActorIndex; + + var scripts = dbg.scripts[jsonObj.location.url], + tmpScript = null; + + if (scripts) { + var breakLine = jsonObj.location.line, + off = -1; + for (var n=0; n < scripts.length; n++) { + offsets = scripts[n].getLineOffsets(breakLine); + if (offsets.length > 0) { + off = offsets[0]; + tmpScript = scripts[n]; + break; + } + } + if (off >= 0) { + tmpScript.setBreakpoint(off, breakpointHandler); + // return ({commandname : "break", + // success : true, + // jsfilename : md[2], + // breakpointlinenumber : breakLine}); + } else { + // return ({commandname : "break", + // success : false, + // stringResult : "no valid offsets at that line"}); + } + } else { + // return ({commandname : "break", + // success : false, + // jsfilename : md[2], + // stringResult : "Invalid script name"}); + } + + _RDPWrite({ from: "tabThreadActor111", "actor":"breakpointActor"+breakpointActorIndex}); + // jsonObj.location.url + // jsonObj.location.line + } + else if (isStringStartWith(jsonObj.to, "breakpointActor") && jsonObj.type === "delete") + { + _RDPWrite({ from: jsonObj.to }); + } + else if (jsonObj.to === "tabThreadActor111" && jsonObj.type === "frames") + { + dbg.log("sdfsld...."+breakpointFrame.arguments); + + // var arr = breakpointFrame.getOwnPropertyNames(); + // log("names: "+ arr); + + var parentEnv = breakpointFrame.environment.parent; + log("parentEnv:" + parentEnv); + log("parentEnv.type:" + parentEnv.type); + log("parentEnv.actor:" + parentEnv.actor); + log("parentEnv.functionName:" + parentEnv.functionName); + log("parentEnv.object:" + parentEnv.object); + log("parentEnv.object.type:" + parentEnv.object.type); + log("parentEnv.object.class:" + parentEnv.object.class); + var keys = Object.keys(parentEnv.object); + log("keys: " + keys); + + parentEnv = parentEnv.parent; + log("2parentEnv:" + parentEnv); + log("parentEnv.type:" + parentEnv.type); + log("parentEnv.actor:" + parentEnv.actor); + log("parentEnv.functionName:" + parentEnv.functionName); + + var bindings = parentEnv.bindings; + log("bindings:" + bindings); + + var args = bindings.arguments; + log("args:"+args); + + var vars = bindings.variables; + log("vars:" + vars); + + // if (breakpointFrame != null) + { + dbg.log("get frames....."); + var obj = { + "from": "tabThreadActor111", + "frame":{ "actor":"frameActor", "depth":1, + "type":"call", "where":{ "url":"sample.js", "line":3 }, + "environment":{ "type":"function", "actor":"gFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"gActor" }, + "functionName":"g", + "bindings":{ arguments: [ { "y": { "value":"argument to g", "configurable":"false", + "writable":true, "enumerable":true } } ] }, + "parent":{ "type":"function", "actor":"fFrameActor", + "function":{ "type":"object", "class":"Function", "actor":"fActor" }, + "functionName":"f", + "bindings": { arguments: [ { "x": { "value":"argument to f", "configurable":"false", + "writable":true, "enumerable":true } } ], + variables: { "z": { "value":"value of z", "configurable":"false", + "writable":true, "enumerable":true } } }, + "parent":{ "type":"object", "actor":"globalCodeActor", + "object":{ "type":"object", "class":"Global", + "actor":"globalObjectActor" } + } + } + }, + "callee":"gActor", "calleeName":"g", + "this":{ "type":"object", "class":"Function", "actor":"gActor" }, + "arguments":["argument to g"] + }}; + + _RDPWrite(obj); + + breakpointFrame = null; + } + } + else if (jsonObj.type === "interrupt") + { + _RDPWrite({ + from: "tabThreadActor111", + type: "resumed" + }); + } + + + + return; // remove Carriage Return's inputstr = inputstr.replace(/\r+/, ""); @@ -570,9 +941,15 @@ _printHelp = function() { dbg.scripts = []; +_RDPWrite = function(jsonObj){ + var buf = JSON.stringify(jsonObj); + _bufferWrite("" + buf.length + ":" + buf); +}; + dbg.onNewScript = function (script) { + dbg.log("onNewScript, "+script.url); // skip if the url is this script - var last = script.url.split("/").pop(); + // var last = script.url.split("/").pop(); var children = script.getChildScripts(), arr = [script].concat(children); @@ -584,9 +961,13 @@ dbg.onNewScript = function (script) { var offsets = arr[i].getLineOffsets(j); dbg.log(" off: " + offsets.join(",") + "; line: " + j); } - } - */ - dbg.scripts[last] = arr; + }*/ + + dbg.scripts["file://"+script.url] = arr; + + // dbg.log("source: "+script.source.text); + + }; dbg.onError = function (frame, report) { @@ -596,6 +977,11 @@ dbg.onError = function (frame, report) { dbg.log("!! exception"); }; +dbg.onDebuggerStatement = function(frame) +{ + dbg.log("onDebuggerStatement..."); +}; + this._prepareDebugger = function (global) { var tmp = new Debugger(global); tmp.onNewScript = dbg.onNewScript; From b5d02d8cca1381c25aaa2e670d71ee04a17accae Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 7 Oct 2013 17:19:00 +0800 Subject: [PATCH 051/116] issue #2823: firefox debugger step ok. --- .../project.pbxproj.REMOVED.git-id | 2 +- cocos2dx/platform/CCFileUtils.cpp | 1 - .../TestJavascript/Classes/AppDelegate.cpp | 5 +- .../project.pbxproj.REMOVED.git-id | 2 +- .../javascript/bindings/ScriptingCore.cpp | 145 +- .../cocos2d_specifics.cpp.REMOVED.git-id | 2 +- .../bindings/js/debugger/DevToolsUtils.js | 74 + .../bindings/js/debugger/actors/gcli.js | 77 + .../bindings/js/debugger/actors/inspector.js | 2100 ++++++++++++ .../bindings/js/debugger/actors/profiler.js | 218 ++ .../bindings/js/debugger/actors/root.js | 329 ++ .../bindings/js/debugger/actors/script.js | 2946 +++++++++++++++++ .../bindings/js/debugger/actors/string.js | 145 + .../js/debugger/actors/styleeditor.js | 740 +++++ .../bindings/js/debugger/actors/webapps.js | 397 +++ .../bindings/js/debugger/actors/webbrowser.js | 866 +++++ .../bindings/js/debugger/actors/webconsole.js | 1555 +++++++++ .../bindings/js/debugger/core/promise.js | 294 ++ .../js/debugger/jsb-tests/test_dbgglobal.js | 82 + .../js/debugger/jsb-tests/testactors.js | 98 + .../javascript/bindings/js/debugger/main.js | 921 ++++++ .../bindings/js/debugger/protocol.js | 1219 +++++++ .../js/debugger/tests/mochitest/Makefile.in | 31 + .../tests/mochitest/inspector-helpers.js | 293 ++ .../mochitest/inspector-traversal-data.html | 54 + .../js/debugger/tests/mochitest/moz.build | 5 + .../nonchrome_unsafeDereference.html | 8 + .../mochitest/test_inspector-changeattrs.html | 102 + .../mochitest/test_inspector-changevalue.html | 84 + .../test_inspector-mutations-attr.html | 127 + .../test_inspector-mutations-childlist.html | 313 ++ .../test_inspector-mutations-frameload.html | 217 ++ .../test_inspector-mutations-value.html | 151 + .../test_inspector-pseudoclass-lock.html | 177 + .../mochitest/test_inspector-release.html | 94 + .../mochitest/test_inspector-retain.html | 183 + .../mochitest/test_inspector-traversal.html | 332 ++ .../mochitest/test_unsafeDereference.html | 52 + .../bindings/js/debugger/tests/moz.build | 11 + .../js/debugger/tests/unit/head_dbg.js | 328 ++ .../tests/unit/post_init_global_actors.js | 17 + .../tests/unit/post_init_tab_actors.js | 17 + .../tests/unit/pre_init_global_actors.js | 17 + .../tests/unit/pre_init_tab_actors.js | 17 + .../tests/unit/registertestactors-01.js | 15 + .../tests/unit/registertestactors-02.js | 13 + .../unit/source-map-data/sourcemapped.coffee | 6 + .../unit/source-map-data/sourcemapped.map | 10 + .../js/debugger/tests/unit/sourcemapped.js | 16 + .../js/debugger/tests/unit/test_add_actors.js | 87 + .../js/debugger/tests/unit/test_attach.js | 37 + .../tests/unit/test_blackboxing-01.js | 178 + .../tests/unit/test_blackboxing-02.js | 104 + .../tests/unit/test_blackboxing-03.js | 104 + .../tests/unit/test_blackboxing-04.js | 79 + .../tests/unit/test_blackboxing-05.js | 79 + .../debugger/tests/unit/test_breakpoint-01.js | 62 + .../debugger/tests/unit/test_breakpoint-02.js | 50 + .../debugger/tests/unit/test_breakpoint-03.js | 68 + .../debugger/tests/unit/test_breakpoint-04.js | 67 + .../debugger/tests/unit/test_breakpoint-05.js | 70 + .../debugger/tests/unit/test_breakpoint-06.js | 76 + .../debugger/tests/unit/test_breakpoint-07.js | 73 + .../debugger/tests/unit/test_breakpoint-08.js | 71 + .../debugger/tests/unit/test_breakpoint-09.js | 77 + .../debugger/tests/unit/test_breakpoint-10.js | 77 + .../debugger/tests/unit/test_breakpoint-11.js | 76 + .../debugger/tests/unit/test_breakpoint-12.js | 99 + .../tests/unit/test_breakpointstore.js | 21 + .../js/debugger/tests/unit/test_dbgactor.js | 118 + .../unit/test_dbgclient_debuggerstatement.js | 74 + .../js/debugger/tests/unit/test_dbgglobal.js | 65 + .../js/debugger/tests/unit/test_dbgsocket.js | 164 + .../js/debugger/tests/unit/test_eval-01.js | 58 + .../js/debugger/tests/unit/test_eval-02.js | 48 + .../js/debugger/tests/unit/test_eval-03.js | 50 + .../js/debugger/tests/unit/test_eval-04.js | 69 + .../js/debugger/tests/unit/test_eval-05.js | 54 + .../debugger/tests/unit/test_frameactor-01.js | 44 + .../debugger/tests/unit/test_frameactor-02.js | 46 + .../debugger/tests/unit/test_frameactor-03.js | 48 + .../debugger/tests/unit/test_frameactor-04.js | 92 + .../debugger/tests/unit/test_frameactor-05.js | 90 + .../tests/unit/test_framearguments-01.js | 51 + .../tests/unit/test_framebindings-01.js | 77 + .../tests/unit/test_framebindings-02.js | 62 + .../tests/unit/test_framebindings-03.js | 69 + .../tests/unit/test_framebindings-04.js | 84 + .../tests/unit/test_framebindings-05.js | 62 + .../tests/unit/test_framebindings-06.js | 58 + .../tests/unit/test_frameclient-01.js | 54 + .../tests/unit/test_frameclient-02.js | 47 + .../tests/unit/test_functiongrips-01.js | 94 + .../tests/unit/test_getyoungestframe.js | 30 + .../js/debugger/tests/unit/test_interrupt.js | 50 + .../tests/unit/test_listsources-01.js | 58 + .../tests/unit/test_listsources-02.js | 52 + .../tests/unit/test_listsources-03.js | 52 + .../tests/unit/test_longstringactor.js | 107 + .../tests/unit/test_longstringgrips-01.js | 71 + .../tests/unit/test_longstringgrips-02.js | 60 + .../tests/unit/test_nativewrappers.js | 30 + .../debugger/tests/unit/test_new_source-01.js | 40 + .../debugger/tests/unit/test_nsjsinspector.js | 59 + .../tests/unit/test_objectgrips-01.js | 49 + .../tests/unit/test_objectgrips-02.js | 56 + .../tests/unit/test_objectgrips-03.js | 64 + .../tests/unit/test_objectgrips-04.js | 67 + .../tests/unit/test_objectgrips-05.js | 57 + .../tests/unit/test_objectgrips-06.js | 57 + .../tests/unit/test_objectgrips-07.js | 65 + .../tests/unit/test_pause_exceptions-01.js | 51 + .../tests/unit/test_pause_exceptions-02.js | 48 + .../tests/unit/test_pauselifetime-01.js | 55 + .../tests/unit/test_pauselifetime-02.js | 57 + .../tests/unit/test_pauselifetime-03.js | 62 + .../tests/unit/test_pauselifetime-04.js | 49 + .../tests/unit/test_profiler_activation.js | 66 + .../tests/unit/test_profiler_actor.js | 168 + .../tests/unit/test_protocol_children.js | 434 +++ .../tests/unit/test_protocol_longstring.js | 207 ++ .../tests/unit/test_protocol_simple.js | 276 ++ .../tests/unit/test_register_actor.js | 43 + .../js/debugger/tests/unit/test_source-01.js | 72 + .../debugger/tests/unit/test_sourcemaps-01.js | 64 + .../debugger/tests/unit/test_sourcemaps-02.js | 69 + .../debugger/tests/unit/test_sourcemaps-03.js | 149 + .../debugger/tests/unit/test_sourcemaps-04.js | 57 + .../debugger/tests/unit/test_sourcemaps-05.js | 57 + .../debugger/tests/unit/test_sourcemaps-06.js | 86 + .../debugger/tests/unit/test_sourcemaps-07.js | 67 + .../debugger/tests/unit/test_sourcemaps-08.js | 52 + .../unit/test_sources_backwards_compat-01.js | 77 + .../unit/test_sources_backwards_compat-02.js | 54 + .../debugger/tests/unit/test_stepping-01.js | 74 + .../debugger/tests/unit/test_stepping-02.js | 74 + .../debugger/tests/unit/test_stepping-03.js | 53 + .../debugger/tests/unit/test_stepping-04.js | 65 + .../debugger/tests/unit/test_stepping-05.js | 92 + .../debugger/tests/unit/test_stepping-06.js | 85 + .../tests/unit/test_threadlifetime-01.js | 59 + .../tests/unit/test_threadlifetime-02.js | 60 + .../tests/unit/test_threadlifetime-03.js | 82 + .../tests/unit/test_threadlifetime-04.js | 54 + .../tests/unit/test_threadlifetime-05.js | 84 + .../tests/unit/test_threadlifetime-06.js | 72 + .../tests/unit/test_unsafeDereference.js | 134 + .../js/debugger/tests/unit/testactors.js | 98 + .../debugger/tests/unit/testcompatactors.js | 119 + .../js/debugger/tests/unit/xpcshell.ini | 144 + .../bindings/js/debugger/transport.js | 285 ++ .../javascript/bindings/js/jsb_debugger.js | 154 +- 152 files changed, 23120 insertions(+), 153 deletions(-) create mode 100644 scripting/javascript/bindings/js/debugger/DevToolsUtils.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/gcli.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/inspector.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/profiler.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/root.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/script.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/string.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/styleeditor.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/webapps.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/webbrowser.js create mode 100644 scripting/javascript/bindings/js/debugger/actors/webconsole.js create mode 100644 scripting/javascript/bindings/js/debugger/core/promise.js create mode 100644 scripting/javascript/bindings/js/debugger/jsb-tests/test_dbgglobal.js create mode 100644 scripting/javascript/bindings/js/debugger/jsb-tests/testactors.js create mode 100644 scripting/javascript/bindings/js/debugger/main.js create mode 100644 scripting/javascript/bindings/js/debugger/protocol.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/Makefile.in create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/inspector-helpers.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/inspector-traversal-data.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/moz.build create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/nonchrome_unsafeDereference.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-changeattrs.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-changevalue.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-mutations-attr.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-mutations-childlist.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-mutations-frameload.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-mutations-value.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-pseudoclass-lock.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-release.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-retain.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_inspector-traversal.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/mochitest/test_unsafeDereference.html create mode 100644 scripting/javascript/bindings/js/debugger/tests/moz.build create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/head_dbg.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/post_init_global_actors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/post_init_tab_actors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/pre_init_global_actors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/pre_init_tab_actors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/registertestactors-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/registertestactors-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/source-map-data/sourcemapped.coffee create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/source-map-data/sourcemapped.map create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/sourcemapped.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_add_actors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_attach.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_blackboxing-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_blackboxing-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_blackboxing-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_blackboxing-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_blackboxing-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-07.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-08.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-09.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-10.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-11.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpoint-12.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_breakpointstore.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_dbgactor.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_dbgclient_debuggerstatement.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_dbgglobal.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_dbgsocket.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_eval-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_eval-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_eval-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_eval-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_eval-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameactor-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameactor-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameactor-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameactor-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameactor-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framearguments-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_framebindings-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameclient-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_frameclient-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_functiongrips-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_getyoungestframe.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_interrupt.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_listsources-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_listsources-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_listsources-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_longstringactor.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_longstringgrips-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_longstringgrips-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_nativewrappers.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_new_source-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_nsjsinspector.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_objectgrips-07.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pause_exceptions-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pause_exceptions-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pauselifetime-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pauselifetime-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pauselifetime-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_pauselifetime-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_profiler_activation.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_profiler_actor.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_protocol_children.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_protocol_longstring.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_protocol_simple.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_register_actor.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_source-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-07.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sourcemaps-08.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sources_backwards_compat-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_sources_backwards_compat-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_stepping-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-01.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-02.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-03.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-04.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-05.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_threadlifetime-06.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/test_unsafeDereference.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/testactors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/testcompatactors.js create mode 100644 scripting/javascript/bindings/js/debugger/tests/unit/xpcshell.ini create mode 100644 scripting/javascript/bindings/js/debugger/transport.js diff --git a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index 48555d6a5d..c1720e39d7 100644 --- a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -3959af89b6bbc8fb982769d22d2591991107d6e5 \ No newline at end of file +8ad5afb135018cfa93b3aee4dddbea24f0ef9b9e \ No newline at end of file diff --git a/cocos2dx/platform/CCFileUtils.cpp b/cocos2dx/platform/CCFileUtils.cpp index 6f286607fb..0db8c28f1a 100644 --- a/cocos2dx/platform/CCFileUtils.cpp +++ b/cocos2dx/platform/CCFileUtils.cpp @@ -618,7 +618,6 @@ std::string FileUtils::fullPathForFilename(const std::string &filename) for (auto searchIt = _searchPathArray.begin(); searchIt != _searchPathArray.end(); ++searchIt) { for (auto resolutionIt = _searchResolutionsOrderArray.begin(); resolutionIt != _searchResolutionsOrderArray.end(); ++resolutionIt) { - fullpath = this->getPathForFilename(newFilename, *resolutionIt, *searchIt); if (fullpath.length() > 0) diff --git a/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp b/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp index 4b7b6c87ff..fc44e06b9b 100644 --- a/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp +++ b/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp @@ -41,6 +41,9 @@ bool AppDelegate::applicationDidFinishLaunching() // set FPS. the default value is 1.0/60 if you don't call this pDirector->setAnimationInterval(1.0 / 60); + FileUtils::getInstance()->addSearchPath("res"); + FileUtils::getInstance()->addSearchPath("js"); + ScriptingCore* sc = ScriptingCore::getInstance(); sc->addRegisterCallback(register_all_cocos2dx); sc->addRegisterCallback(register_all_cocos2dx_extension); @@ -54,8 +57,6 @@ bool AppDelegate::applicationDidFinishLaunching() sc->addRegisterCallback(register_CCBuilderReader); sc->start(); - - FileUtils::getInstance()->addSearchPath("res"); auto pEngine = ScriptingCore::getInstance(); ScriptEngineManager::getInstance()->setScriptEngine(pEngine); diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index ec33bf839a..0cf8b5aa58 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -381c282bed409f4b41a82505460d4d6c84ba70ab \ No newline at end of file +0017c1d76ce42fd252ff8245774d5a276e278115 \ No newline at end of file diff --git a/scripting/javascript/bindings/ScriptingCore.cpp b/scripting/javascript/bindings/ScriptingCore.cpp index 0ed5b8eb68..9c9370e79b 100644 --- a/scripting/javascript/bindings/ScriptingCore.cpp +++ b/scripting/javascript/bindings/ScriptingCore.cpp @@ -662,9 +662,10 @@ JSBool ScriptingCore::executeScript(JSContext *cx, uint32_t argc, jsval *vp) if (argc == 2 && argv[1].isString()) { JSString* globalName = JSVAL_TO_STRING(argv[1]); JSStringWrapper name(globalName); - js::RootedObject* rootedGlobal = globals[name]; - if (rootedGlobal) { - res = ScriptingCore::getInstance()->runScript(path, rootedGlobal->get()); +// js::RootedObject* rootedGlobal = globals[name]; + JSObject* debugObj = ScriptingCore::getInstance()->getDebugGlobal(); + if (debugObj) { + res = ScriptingCore::getInstance()->runScript(path, debugObj); } else { JS_ReportError(cx, "Invalid global object: %s", (char*)name); return JS_FALSE; @@ -1964,9 +1965,9 @@ void ScriptingCore::enableDebugger() { JS_DefineFunction(cx_, debugGlobal_, "_bufferRead", JSBDebug_BufferRead, 0, JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(cx_, debugGlobal_, "_lockVM", JSBDebug_LockExecution, 2, JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(cx_, debugGlobal_, "_unlockVM", JSBDebug_UnlockExecution, 0, JSPROP_READONLY | JSPROP_PERMANENT); - + + runScript("jsb_debugger.js", debugGlobal_); -// runScript("SysTest/script.js", debugGlobal_); CCLOG("before _prepareDebugger..."); // prepare the debugger @@ -2266,7 +2267,6 @@ static void serverEntryPoint(void) listen(s, 1); - int recieveIndex = 0; while (true) { clientSocket = accept(s, NULL, NULL); @@ -2284,144 +2284,13 @@ static void serverEntryPoint(void) // process any input, send any output clearBuffers(); -// if (recieveIndex == 0) -// { -// replyToClient(clientSocket, "{\"from\":\"root\",\"applicationType\":\"browser\",\"traits\":{\"sources\": true}}"); -// ++recieveIndex; -// } - - char buf[1024] = {0}; int readBytes = 0; while ((readBytes = ::recv(clientSocket, buf, sizeof(buf), 0)) > 0) { buf[readBytes] = '\0'; - TRACE_DEBUGGER_SERVER("debug server : received command >%s", buf); +// TRACE_DEBUGGER_SERVER("debug server : received command >%s", buf); -// if (recieveIndex == 1) -// { -// replyToClient(clientSocket, "{ \"from\":\"root\", \"tabs\":[{ \"actor\":\"JSBTabActor\", \"title\":\"Hello cocos2d-x JSB\", \"url\":\"http://www.cocos2d-x.org\" }], \"selected\":0 }"); -// } -// else if (recieveIndex == 2) -// { -// replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabAttached\", \"threadActor\":\"tabThreadActor111\" }"); -// } -// else if (recieveIndex == 3) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"paused\",\ -// \"actor\": \"JSBTabActor\",\ -// \"poppedFrames\": [],\ -// \"why\": {\ -// \"type\": \"attached\"\ -// }\ -// }"); -// -// -// -// //replyToClient(clientSocket, "{ \"from\":\"JSBTabActor\", \"type\":\"tabNavigated\", \"state\":\"start\", \"url\":\"my_url.js\" }"); -// } -// else if (recieveIndex == 4) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"newSource\",\ -// \"source\": {\ -// \"actor\": \"source_actor1\",\ -// \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ -// \"isBlackBoxed\": false\ -// }\ -// }"); -// -// replyToClient(clientSocket, -// "{\ -// \"sources\": [\ -// {\ -// \"actor\": \"source_actor1\",\ -// \"url\": \"file://~/Project/cocos2d-html5/cocos2d/CCDirector.js\",\ -// \"isBlackBoxed\": false\ -// }\ -// ],\ -// \"from\": \"tabThreadActor111\"\ -// }"); -// } -// else if (recieveIndex == 5) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"source_actor1\",\ -// \"source\": {\ -// \"type\": \"longString\",\ -// \"initial\": \"var cc = cc || {}; cc.Director = {};\",\ -// \"length\": 100,\ -// \"actor\": \"conn2.longString48\"\ -// }\ -// }"); -// } -// else if (recieveIndex == 6) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"conn2.longString48\",\ -// \"substring\": \"var cc = cc || {}; cc.Director = {};\ -//\\ncc.Sprite = {};\"\ -// }"); -// -// -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"resumed\"\ -// }"); -// } -// else if (recieveIndex == 7) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"resumed\"\ -// }"); -// } -// else if (recieveIndex == 8) -// { -// replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); -// } -// else if (recieveIndex == 9) -// { -// replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); -// } -// else if (recieveIndex == 10) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"resumed\"\ -// }"); -// } -// else -// { -// -// -// std::string recvBuf = buf; -// auto found = recvBuf.find("setBreakpoint"); -// if (found != std::string::npos) -// { -// replyToClient(clientSocket, "{ \"from\":\"tabThreadActor111\", \"actor\":\"breakActor\"}");//, \"actualLocation\":2 }"); -// } -// -// found = recvBuf.find("delete"); -// if (found != std::string::npos) -// { -// replyToClient(clientSocket, "{ \"from\":\"breakActor\" }"); -// } -// -// found = recvBuf.find("interrupt"); -// if (found != std::string::npos) -// { -// replyToClient(clientSocket, "{\ -// \"from\": \"tabThreadActor111\",\ -// \"type\": \"resumed\"\ -// }"); -// } -// -// } -// ++recieveIndex; // no other thread is using this inData.append(buf); // process any input, send any output diff --git a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id index 9ff7a17801..9aaad3f31f 100644 --- a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id +++ b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id @@ -1 +1 @@ -db6aaa41d0756117258eebb759cd6420f66071e0 \ No newline at end of file +ceb78008acf831592a416d7dfa85a9dfd0ddae75 \ No newline at end of file diff --git a/scripting/javascript/bindings/js/debugger/DevToolsUtils.js b/scripting/javascript/bindings/js/debugger/DevToolsUtils.js new file mode 100644 index 0000000000..8b8fb19feb --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/DevToolsUtils.js @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var dump = function(msg) { + log(msg); +}; + +/* General utilities used throughout devtools. */ + +/* Turn the error e into a string, without fail. */ +this.safeErrorString = function safeErrorString(aError) { + try { + var s = aError.toString(); + if (typeof s === "string") + return s; + } catch (ee) { } + + return ""; +} + +/** + * Report that |aWho| threw an exception, |aException|. + */ +this.reportException = function reportException(aWho, aException) { + let msg = aWho + " threw an exception: " + safeErrorString(aException); + if (aException.stack) { + msg += "\nCall stack:\n" + aException.stack; + } + + dump(msg + "\n"); + + // if (Components.utils.reportError) { + // /* + // * Note that the xpcshell test harness registers an observer for + // * console messages, so when we're running tests, this will cause + // * the test to quit. + // */ + // Components.utils.reportError(msg); + // } +} + +/** + * Given a handler function that may throw, return an infallible handler + * function that calls the fallible handler, and logs any exceptions it + * throws. + * + * @param aHandler function + * A handler function, which may throw. + * @param aName string + * A name for aHandler, for use in error messages. If omitted, we use + * aHandler.name. + * + * (SpiderMonkey does generate good names for anonymous functions, but we + * don't have a way to get at them from JavaScript at the moment.) + */ +this.makeInfallible = function makeInfallible(aHandler, aName) { + if (!aName) + aName = aHandler.name; + + return function (/* arguments */) { + try { + return aHandler.apply(this, arguments); + } catch (ex) { + let who = "Handler function"; + if (aName) { + who += " " + aName; + } + reportException(who, ex); + } + } +} diff --git a/scripting/javascript/bindings/js/debugger/actors/gcli.js b/scripting/javascript/bindings/js/debugger/actors/gcli.js new file mode 100644 index 0000000000..1f3c914d4e --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/gcli.js @@ -0,0 +1,77 @@ +/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +let { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); + +XPCOMUtils.defineLazyModuleGetter(this, "console", + "resource://gre/modules/devtools/Console.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils", + "resource:///modules/devtools/DeveloperToolbar.jsm"); + +XPCOMUtils.defineLazyGetter(this, "require", function() { + let { require } = Cu.import("resource://gre/modules/devtools/Require.jsm", {}); + Cu.import("resource://gre/modules/devtools/gcli.jsm", {}); + return require; +}); + +XPCOMUtils.defineLazyGetter(this, "canon", () => require("gcli/canon")); +XPCOMUtils.defineLazyGetter(this, "Requisition", () => require("gcli/cli").Requisition); +XPCOMUtils.defineLazyGetter(this, "util", () => require("util/util")); + + +/** + * Manage remote connections that want to talk to GCLI + * @constructor + * @param connection The connection to the client, DebuggerServerConnection + * @param parentActor Optional, the parent actor + */ +function GcliActor(connection, parentActor) { + this.connection = connection; +} + +GcliActor.prototype.actorPrefix = "gcli"; + +GcliActor.prototype.disconnect = function() { +}; + +GcliActor.prototype.getCommandSpecs = function(request) { + return { commandSpecs: canon.getCommandSpecs() }; +}; + +GcliActor.prototype.execute = function(request) { + let windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + let chromeWindow = windowMediator.getMostRecentWindow("navigator:browser"); + let contentWindow = chromeWindow.gBrowser.selectedTab.linkedBrowser.contentWindow; + + let environment = CommandUtils.createEnvironment(chromeWindow.document, + contentWindow.document); + + let requisition = new Requisition(environment); + requisition.updateExec(request.typed).then(output => { + return output.promise.then(() => { + this.connection.send({ + from: this.actorID, + requestId: request.requestId, + data: output.data, + type: output.type, + error: output.error + }); + }); + }).then(null, console.error); +}; + +GcliActor.prototype.requestTypes = { + getCommandSpecs: GcliActor.prototype.getCommandSpecs, + execute: GcliActor.prototype.execute, +}; + +addTabActor(GcliActor, "gcliActor"); +addGlobalActor(GcliActor, "gcliActor"); diff --git a/scripting/javascript/bindings/js/debugger/actors/inspector.js b/scripting/javascript/bindings/js/debugger/actors/inspector.js new file mode 100644 index 0000000000..ac07ad103a --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/inspector.js @@ -0,0 +1,2100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Here's the server side of the remote inspector. + * + * The WalkerActor is the client's view of the debuggee's DOM. It's gives + * the client a tree of NodeActor objects. + * + * The walker presents the DOM tree mostly unmodified from the source DOM + * tree, but with a few key differences: + * + * - Empty text nodes are ignored. This is pretty typical of developer + * tools, but maybe we should reconsider that on the server side. + * - iframes with documents loaded have the loaded document as the child, + * the walker provides one big tree for the whole document tree. + * + * There are a few ways to get references to NodeActors: + * + * - When you first get a WalkerActor reference, it comes with a free + * reference to the root document's node. + * - Given a node, you can ask for children, siblings, and parents. + * - You can issue querySelector and querySelectorAll requests to find + * other elements. + * - Requests that return arbitrary nodes from the tree (like querySelector + * and querySelectorAll) will also return any nodes the client hasn't + * seen in order to have a complete set of parents. + * + * Once you have a NodeFront, you should be able to answer a few questions + * without further round trips, like the node's name, namespace/tagName, + * attributes, etc. Other questions (like a text node's full nodeValue) + * might require another round trip. + * + * The protocol guarantees that the client will always know the parent of + * any node that is returned by the server. This means that some requests + * (like querySelector) will include the extra nodes needed to satisfy this + * requirement. The client keeps track of this parent relationship, so the + * node fronts form a tree that is a subset of the actual DOM tree. + */ + +const {Cc, Ci, Cu} = require("chrome"); + +const protocol = require("devtools/server/protocol"); +const {Arg, Option, method, RetVal, types} = protocol; +const {LongStringActor, ShortLongString} = require("devtools/server/actors/string"); +const promise = require("sdk/core/promise"); +const object = require("sdk/util/object"); +const events = require("sdk/event/core"); +const { Unknown } = require("sdk/platform/xpcom"); +const { Class } = require("sdk/core/heritage"); + +const PSEUDO_CLASSES = [":hover", ":active", ":focus"]; + +Cu.import("resource://gre/modules/Services.jsm"); + +exports.register = function(handle) { + handle.addTabActor(InspectorActor, "inspectorActor"); +}; + +exports.unregister = function(handle) { + handle.removeTabActor(InspectorActor); +}; + +// XXX: A poor man's makeInfallible until we move it out of transport.js +// Which should be very soon. +function makeInfallible(handler) { + return function(...args) { + try { + return handler.apply(this, args); + } catch(ex) { + console.error(ex); + } + return undefined; + } +} + +// A resolve that hits the main loop first. +function delayedResolve(value) { + let deferred = promise.defer(); + Services.tm.mainThread.dispatch(makeInfallible(function delayedResolveHandler() { + deferred.resolve(value); + }), 0); + return deferred.promise; +} + +/** + * We only send nodeValue up to a certain size by default. This stuff + * controls that size. + */ +exports.DEFAULT_VALUE_SUMMARY_LENGTH = 50; +var gValueSummaryLength = exports.DEFAULT_VALUE_SUMMARY_LENGTH; + +exports.getValueSummaryLength = function() { + return gValueSummaryLength; +}; + +exports.setValueSummaryLength = function(val) { + gValueSummaryLength = val; +}; + +/** + * Server side of the node actor. + */ +var NodeActor = protocol.ActorClass({ + typeName: "domnode", + + initialize: function(walker, node) { + protocol.Actor.prototype.initialize.call(this, null); + this.walker = walker; + this.rawNode = node; + }, + + toString: function() { + return "[NodeActor " + this.actorID + " for " + this.rawNode.toString() + "]"; + }, + + /** + * Instead of storing a connection object, the NodeActor gets its connection + * from its associated walker. + */ + get conn() this.walker.conn, + + // Returns the JSON representation of this object over the wire. + form: function(detail) { + let parentNode = this.walker.parentNode(this); + + // Estimate the number of children. + let numChildren = this.rawNode.childNodes.length; + if (numChildren === 0 && + (this.rawNode.contentDocument || this.rawNode.getSVGDocument)) { + // This might be an iframe with virtual children. + numChildren = 1; + } + + let form = { + actor: this.actorID, + parent: parentNode ? parentNode.actorID : undefined, + nodeType: this.rawNode.nodeType, + namespaceURI: this.namespaceURI, + nodeName: this.rawNode.nodeName, + numChildren: numChildren, + + // doctype attributes + name: this.rawNode.name, + publicId: this.rawNode.publicId, + systemId: this.rawNode.systemId, + + attrs: this.writeAttrs(), + + pseudoClassLocks: this.writePseudoClassLocks(), + }; + + if (this.rawNode.ownerDocument && + this.rawNode.ownerDocument.documentElement === this.rawNode) { + form.isDocumentElement = true; + } + + if (this.rawNode.nodeValue) { + // We only include a short version of the value if it's longer than + // gValueSummaryLength + if (this.rawNode.nodeValue.length > gValueSummaryLength) { + form.shortValue = this.rawNode.nodeValue.substring(0, gValueSummaryLength); + form.incompleteValue = true; + } else { + form.shortValue = this.rawNode.nodeValue; + } + } + + return form; + }, + + writeAttrs: function() { + if (!this.rawNode.attributes) { + return undefined; + } + return [{namespace: attr.namespace, name: attr.name, value: attr.value } + for (attr of this.rawNode.attributes)]; + }, + + writePseudoClassLocks: function() { + if (this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) { + return undefined; + } + let ret = undefined; + for (let pseudo of PSEUDO_CLASSES) { + if (DOMUtils.hasPseudoClassLock(this.rawNode, pseudo)) { + ret = ret || []; + ret.push(pseudo); + } + } + return ret; + }, + + /** + * Returns a LongStringActor with the node's value. + */ + getNodeValue: method(function() { + return new LongStringActor(this.conn, this.rawNode.nodeValue || ""); + }, { + request: {}, + response: { + value: RetVal("longstring") + } + }), + + /** + * Set the node's value to a given string. + */ + setNodeValue: method(function(value) { + this.rawNode.nodeValue = value; + }, { + request: { value: Arg(0) }, + response: {} + }), + + /** + * Modify a node's attributes. Passed an array of modifications + * similar in format to "attributes" mutations. + * { + * attributeName: + * attributeNamespace: + * newValue: - If null or undefined, the attribute + * will be removed. + * } + * + * Returns when the modifications have been made. Mutations will + * be queued for any changes made. + */ + modifyAttributes: method(function(modifications) { + let rawNode = this.rawNode; + for (let change of modifications) { + if (change.newValue == null) { + if (change.attributeNamespace) { + rawNode.removeAttributeNS(change.attributeNamespace, change.attributeName); + } else { + rawNode.removeAttribute(change.attributeName); + } + } else { + if (change.attributeNamespace) { + rawNode.setAttributeNS(change.attributeNamespace, change.attributeName, change.newValue); + } else { + rawNode.setAttribute(change.attributeName, change.newValue); + } + } + } + }, { + request: { + modifications: Arg(0, "array:json") + }, + response: {} + }), + +}); + +/** + * Client side of the node actor. + * + * Node fronts are strored in a tree that mirrors the DOM tree on the + * server, but with a few key differences: + * - Not all children will be necessary loaded for each node. + * - The order of children isn't guaranteed to be the same as the DOM. + * Children are stored in a doubly-linked list, to make addition/removal + * and traversal quick. + * + * Due to the order/incompleteness of the child list, it is safe to use + * the parent node from clients, but the `children` request should be used + * to traverse children. + */ +let NodeFront = protocol.FrontClass(NodeActor, { + initialize: function(conn, form, detail, ctx) { + this._parent = null; // The parent node + this._child = null; // The first child of this node. + this._next = null; // The next sibling of this node. + this._prev = null; // The previous sibling of this node. + protocol.Front.prototype.initialize.call(this, conn, form, detail, ctx); + }, + + /** + * Destroy a node front. The node must have been removed from the + * ownership tree before this is called, unless the whole walker front + * is being destroyed. + */ + destroy: function() { + // If an observer was added on this node, shut it down. + if (this.observer) { + this._observer.disconnect(); + this._observer = null; + } + + protocol.Front.prototype.destroy.call(this); + }, + + // Update the object given a form representation off the wire. + form: function(form, detail, ctx) { + // Shallow copy of the form. We could just store a reference, but + // eventually we'll want to update some of the data. + this._form = object.merge(form); + this._form.attrs = this._form.attrs ? this._form.attrs.slice() : []; + + if (form.parent) { + // Get the owner actor for this actor (the walker), and find the + // parent node of this actor from it, creating a standin node if + // necessary. + let parentNodeFront = ctx.marshallPool().ensureParentFront(form.parent); + this.reparent(parentNodeFront); + } + }, + + /** + * Returns the parent NodeFront for this NodeFront. + */ + parentNode: function() { + return this._parent; + }, + + /** + * Process a mutation entry as returned from the walker's `getMutations` + * request. Only tries to handle changes of the node's contents + * themselves (character data and attribute changes), the walker itself + * will keep the ownership tree up to date. + */ + updateMutation: function(change) { + if (change.type === "attributes") { + // We'll need to lazily reparse the attributes after this change. + this._attrMap = undefined; + + // Update any already-existing attributes. + let found = false; + for (let i = 0; i < this.attributes.length; i++) { + let attr = this.attributes[i]; + if (attr.name == change.attributeName && + attr.namespace == change.attributeNamespace) { + if (change.newValue !== null) { + attr.value = change.newValue; + } else { + this.attributes.splice(i, 1); + } + found = true; + break; + } + } + // This is a new attribute. + if (!found) { + this.attributes.push({ + name: change.attributeName, + namespace: change.attributeNamespace, + value: change.newValue + }); + } + } else if (change.type === "characterData") { + this._form.shortValue = change.newValue; + this._form.incompleteValue = change.incompleteValue; + } else if (change.type === "pseudoClassLock") { + this._form.pseudoClassLocks = change.pseudoClassLocks; + } + }, + + // Some accessors to make NodeFront feel more like an nsIDOMNode + + get id() this.getAttribute("id"), + + get nodeType() this._form.nodeType, + get namespaceURI() this._form.namespaceURI, + get nodeName() this._form.nodeName, + + get className() { + return this.getAttribute("class") || ''; + }, + + get hasChildren() this._form.numChildren > 0, + get numChildren() this._form.numChildren, + + get tagName() this.nodeType === Ci.nsIDOMNode.ELEMENT_NODE ? this.nodeName : null, + get shortValue() this._form.shortValue, + get incompleteValue() !!this._form.incompleteValue, + + get isDocumentElement() !!this._form.isDocumentElement, + + // doctype properties + get name() this._form.name, + get publicId() this._form.publicId, + get systemId() this._form.systemId, + + getAttribute: function(name) { + let attr = this._getAttribute(name); + return attr ? attr.value : null; + }, + hasAttribute: function(name) { + this._cacheAttributes(); + return (name in this._attrMap); + }, + + get attributes() this._form.attrs, + + get pseudoClassLocks() this._form.pseudoClassLocks || [], + hasPseudoClassLock: function(pseudo) { + return this.pseudoClassLocks.some(locked => locked === pseudo); + }, + + getNodeValue: protocol.custom(function() { + if (!this.incompleteValue) { + return delayedResolve(new ShortLongString(this.shortValue)); + } else { + return this._getNodeValue(); + } + }, { + impl: "_getNodeValue" + }), + + /** + * Return a new AttributeModificationList for this node. + */ + startModifyingAttributes: function() { + return AttributeModificationList(this); + }, + + _cacheAttributes: function() { + if (typeof(this._attrMap) != "undefined") { + return; + } + this._attrMap = {}; + for (let attr of this.attributes) { + this._attrMap[attr.name] = attr; + } + }, + + _getAttribute: function(name) { + this._cacheAttributes(); + return this._attrMap[name] || undefined; + }, + + /** + * Set this node's parent. Note that the children saved in + * this tree are unordered and incomplete, so shouldn't be used + * instead of a `children` request. + */ + reparent: function(parent) { + if (this._parent === parent) { + return; + } + + if (this._parent && this._parent._child === this) { + this._parent._child = this._next; + } + if (this._prev) { + this._prev._next = this._next; + } + if (this._next) { + this._next._prev = this._prev; + } + this._next = null; + this._prev = null; + this._parent = parent; + if (!parent) { + // Subtree is disconnected, we're done + return; + } + this._next = parent._child; + if (this._next) { + this._next._prev = this; + } + parent._child = this; + }, + + /** + * Return all the known children of this node. + */ + treeChildren: function() { + let ret = []; + for (let child = this._child; child != null; child = child._next) { + ret.push(child); + } + return ret; + }, + + /** + * Get an nsIDOMNode for the given node front. This only works locally, + * and is only intended as a stopgap during the transition to the remote + * protocol. If you depend on this you're likely to break soon. + */ + rawNode: function(rawNode) { + if (!this.conn._transport._serverConnection) { + console.warn("Tried to use rawNode on a remote connection."); + return null; + } + let actor = this.conn._transport._serverConnection.getActor(this.actorID); + if (!actor) { + // Can happen if we try to get the raw node for an already-expired + // actor. + return null; + } + return actor.rawNode; + } +}); + +/** + * Returned from any call that might return a node that isn't connected to root by + * nodes the child has seen, such as querySelector. + */ +types.addDictType("disconnectedNode", { + // The actual node to return + node: "domnode", + + // Nodes that are needed to connect the node to a node the client has already seen + newNodes: "array:domnode" +}); + +types.addDictType("disconnectedNodeArray", { + // The actual node list to return + nodes: "array:domnode", + + // Nodes that are needed to connect those nodes to the root. + newNodes: "array:domnode" +}); + +types.addDictType("dommutation", {}); + +/** + * Server side of a node list as returned by querySelectorAll() + */ +var NodeListActor = exports.NodeListActor = protocol.ActorClass({ + typeName: "domnodelist", + + initialize: function(walker, nodeList) { + protocol.Actor.prototype.initialize.call(this); + this.walker = walker; + this.nodeList = nodeList; + }, + + destroy: function() { + protocol.Actor.prototype.destroy.call(this); + }, + + /** + * Instead of storing a connection object, the NodeActor gets its connection + * from its associated walker. + */ + get conn() { + return this.walker.conn; + }, + + /** + * Items returned by this actor should belong to the parent walker. + */ + marshallPool: function() { + return this.walker; + }, + + // Returns the JSON representation of this object over the wire. + form: function() { + return { + actor: this.actorID, + length: this.nodeList.length + } + }, + + /** + * Get a single node from the node list. + */ + item: method(function(index) { + let node = this.walker._ref(this.nodeList[index]); + let newNodes = [node for (node of this.walker.ensurePathToRoot(node))]; + return { + node: node, + newNodes: newNodes + } + }, { + request: { item: Arg(0) }, + response: RetVal("disconnectedNode") + }), + + /** + * Get a range of the items from the node list. + */ + items: method(function(start=0, end=this.nodeList.length) { + let items = [this.walker._ref(item) for (item of Array.prototype.slice.call(this.nodeList, start, end))]; + let newNodes = new Set(); + for (let item of items) { + this.walker.ensurePathToRoot(item, newNodes); + } + return { + nodes: items, + newNodes: [node for (node of newNodes)] + } + }, { + request: { + start: Arg(0, "number", { optional: true }), + end: Arg(1, "number", { optional: true }) + }, + response: { nodes: RetVal("disconnectedNodeArray") } + }), + + release: method(function() {}, { release: true }) +}); + +/** + * Client side of a node list as returned by querySelectorAll() + */ +var NodeListFront = exports.NodeLIstFront = protocol.FrontClass(NodeListActor, { + initialize: function(client, form) { + protocol.Front.prototype.initialize.call(this, client, form); + }, + + destroy: function() { + protocol.Front.prototype.destroy.call(this); + }, + + marshallPool: function() { + return this.parent(); + }, + + // Update the object given a form representation off the wire. + form: function(json) { + this.length = json.length; + }, + + item: protocol.custom(function(index) { + return this._item(index).then(response => { + return response.node; + }); + }, { + impl: "_item" + }), + + items: protocol.custom(function(start, end) { + return this._items(start, end).then(response => { + return response.nodes; + }); + }, { + impl: "_items" + }) +}); + +// Some common request/response templates for the dom walker + +let nodeArrayMethod = { + request: { + node: Arg(0, "domnode"), + maxNodes: Option(1), + center: Option(1, "domnode"), + start: Option(1, "domnode"), + whatToShow: Option(1) + }, + response: RetVal(types.addDictType("domtraversalarray", { + nodes: "array:domnode" + })) +}; + +let traversalMethod = { + request: { + node: Arg(0, "domnode"), + whatToShow: Option(1) + }, + response: { + node: RetVal("domnode", {optional: true}) + } +} + +/** + * We need to know when a document is navigating away so that we can kill + * the nodes underneath it. We also need to know when a document is + * navigated to so that we can send a mutation event for the iframe node. + * + * The nsIWebProgressListener is the easiest/best way to watch these + * loads that works correctly with the bfcache. + * + * See nsIWebProgressListener for details + * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIWebProgressListener + */ +var ProgressListener = Class({ + extends: Unknown, + interfaces: ["nsIWebProgressListener", "nsISupportsWeakReference"], + + initialize: function(webProgress) { + Unknown.prototype.initialize.call(this); + this.webProgress = webProgress; + this.webProgress.addProgressListener(this); + }, + + destroy: function() { + this.webProgress.removeProgressListener(this); + }, + + onStateChange: makeInfallible(function stateChange(progress, request, flag, status) { + let isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW; + let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; + if (!(isWindow || isDocument)) { + return; + } + + if (isDocument && (flag & Ci.nsIWebProgressListener.STATE_START)) { + events.emit(this, "windowchange-start", progress.DOMWindow); + } + if (isWindow && (flag & Ci.nsIWebProgressListener.STATE_STOP)) { + events.emit(this, "windowchange-stop", progress.DOMWindow); + } + }), + onProgressChange: function() {}, + onSecurityChange: function() {}, + onStatusChange: function() {}, + onLocationChange: function() {}, +}); + +/** + * Server side of the DOM walker. + */ +var WalkerActor = protocol.ActorClass({ + typeName: "domwalker", + + events: { + "new-mutations" : { + type: "newMutations" + } + }, + + /** + * Create the WalkerActor + * @param DebuggerServerConnection conn + * The server connection. + */ + initialize: function(conn, document, webProgress, options) { + protocol.Actor.prototype.initialize.call(this, conn); + this.rootDoc = document; + this._refMap = new Map(); + this._pendingMutations = []; + this._activePseudoClassLocks = new Set(); + + // Nodes which have been removed from the client's known + // ownership tree are considered "orphaned", and stored in + // this set. + this._orphaned = new Set(); + + // The client can tell the walker that it is interested in a node + // even when it is orphaned with the `retainNode` method. This + // list contains orphaned nodes that were so retained. + this._retainedOrphans = new Set(); + + this.onMutations = this.onMutations.bind(this); + this.onFrameLoad = this.onFrameLoad.bind(this); + this.onFrameUnload = this.onFrameUnload.bind(this); + + this.progressListener = ProgressListener(webProgress); + + events.on(this.progressListener, "windowchange-start", this.onFrameUnload); + events.on(this.progressListener, "windowchange-stop", this.onFrameLoad); + + // Ensure that the root document node actor is ready and + // managed. + this.rootNode = this.document(); + }, + + // Returns the JSON representation of this object over the wire. + form: function() { + return { + actor: this.actorID, + root: this.rootNode.form() + } + }, + + toString: function() { + return "[WalkerActor " + this.actorID + "]"; + }, + + destroy: function() { + this.clearPseudoClassLocks(); + this._activePseudoClassLocks = null; + this.progressListener.destroy(); + this.rootDoc = null; + protocol.Actor.prototype.destroy.call(this); + }, + + release: method(function() {}, { release: true }), + + unmanage: function(actor) { + if (actor instanceof NodeActor) { + if (this._activePseudoClassLocks && + this._activePseudoClassLocks.has(actor)) { + this.clearPsuedoClassLocks(actor); + } + this._refMap.delete(actor.rawNode); + } + protocol.Actor.prototype.unmanage.call(this, actor); + }, + + _ref: function(node) { + let actor = this._refMap.get(node); + if (actor) return actor; + + actor = new NodeActor(this, node); + + // Add the node actor as a child of this walker actor, assigning + // it an actorID. + this.manage(actor); + this._refMap.set(node, actor); + + if (node.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) { + this._watchDocument(actor); + } + return actor; + }, + + /** + * Watch the given document node for mutations using the DOM observer + * API. + */ + _watchDocument: function(actor) { + let node = actor.rawNode; + // Create the observer on the node's actor. The node will make sure + // the observer is cleaned up when the actor is released. + actor.observer = actor.rawNode.defaultView.MutationObserver(this.onMutations); + actor.observer.observe(node, { + attributes: true, + characterData: true, + childList: true, + subtree: true + }); + }, + + /** + * Return the document node that contains the given node, + * or the root node if no node is specified. + * @param NodeActor node + * The node whose document is needed, or null to + * return the root. + */ + document: method(function(node) { + let doc = node ? nodeDocument(node.rawNode) : this.rootDoc; + return this._ref(doc); + }, { + request: { node: Arg(0, "domnode", {optional: true}) }, + response: { node: RetVal("domnode") }, + }), + + /** + * Return the documentElement for the document containing the + * given node. + * @param NodeActor node + * The node whose documentElement is requested, or null + * to use the root document. + */ + documentElement: method(function(node) { + let elt = node ? nodeDocument(node.rawNode).documentElement : this.rootDoc.documentElement; + return this._ref(elt); + }, { + request: { node: Arg(0, "domnode", {optional: true}) }, + response: { node: RetVal("domnode") }, + }), + + /** + * Return all parents of the given node, ordered from immediate parent + * to root. + * @param NodeActor node + * The node whose parents are requested. + * @param object options + * Named options, including: + * `sameDocument`: If true, parents will be restricted to the same + * document as the node. + */ + parents: method(function(node, options={}) { + let walker = documentWalker(node.rawNode); + let parents = []; + let cur; + while((cur = walker.parentNode())) { + if (options.sameDocument && cur.ownerDocument != node.rawNode.ownerDocument) { + break; + } + parents.push(this._ref(cur)); + } + return parents; + }, { + request: { + node: Arg(0, "domnode"), + sameDocument: Option(1) + }, + response: { + nodes: RetVal("array:domnode") + }, + }), + + parentNode: function(node) { + let walker = documentWalker(node.rawNode); + let parent = walker.parentNode(); + if (parent) { + return this._ref(parent); + } + return null; + }, + + /** + * Mark a node as 'retained'. + * + * A retained node is not released when `releaseNode` is called on its + * parent, or when a parent is released with the `cleanup` option to + * `getMutations`. + * + * When a retained node's parent is released, a retained mode is added to + * the walker's "retained orphans" list. + * + * Retained nodes can be deleted by providing the `force` option to + * `releaseNode`. They will also be released when their document + * has been destroyed. + * + * Retaining a node makes no promise about its children; They can + * still be removed by normal means. + */ + retainNode: method(function(node) { + node.retained = true; + }, { + request: { node: Arg(0, "domnode") }, + response: {} + }), + + /** + * Remove the 'retained' mark from a node. If the node was a + * retained orphan, release it. + */ + unretainNode: method(function(node) { + node.retained = false; + if (this._retainedOrphans.has(node)) { + this._retainedOrphans.delete(node); + this.releaseNode(node); + } + }, { + request: { node: Arg(0, "domnode") }, + response: {}, + }), + + /** + * Release actors for a node and all child nodes. + */ + releaseNode: method(function(node, options={}) { + if (node.retained && !options.force) { + this._retainedOrphans.add(node); + return; + } + + if (node.retained) { + // Forcing a retained node to go away. + this._retainedOrphans.delete(node); + } + + let walker = documentWalker(node.rawNode); + + let child = walker.firstChild(); + while (child) { + let childActor = this._refMap.get(child); + if (childActor) { + this.releaseNode(childActor, options); + } + child = walker.nextSibling(); + } + + node.destroy(); + }, { + request: { + node: Arg(0, "domnode"), + force: Option(1) + } + }), + + /** + * Add any nodes between `node` and the walker's root node that have not + * yet been seen by the client. + */ + ensurePathToRoot: function(node, newParents=new Set()) { + if (!node) { + return newParents; + } + let walker = documentWalker(node.rawNode); + let cur; + while ((cur = walker.parentNode())) { + let parent = this._refMap.get(cur); + if (!parent) { + // This parent didn't exist, so hasn't been seen by the client yet. + newParents.add(this._ref(cur)); + } else { + // This parent did exist, so the client knows about it. + return newParents; + } + } + return newParents; + }, + + /** + * Return children of the given node. By default this method will return + * all children of the node, but there are options that can restrict this + * to a more manageable subset. + * + * @param NodeActor node + * The node whose children you're curious about. + * @param object options + * Named options: + * `maxNodes`: The set of nodes returned by the method will be no longer + * than maxNodes. + * `start`: If a node is specified, the list of nodes will start + * with the given child. Mutally exclusive with `center`. + * `center`: If a node is specified, the given node will be as centered + * as possible in the list, given how close to the ends of the child + * list it is. Mutually exclusive with `start`. + * `whatToShow`: A bitmask of node types that should be included. See + * https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter. + * + * @returns an object with three items: + * hasFirst: true if the first child of the node is included in the list. + * hasLast: true if the last child of the node is included in the list. + * nodes: Child nodes returned by the request. + */ + children: method(function(node, options={}) { + if (options.center && options.start) { + throw Error("Can't specify both 'center' and 'start' options."); + } + let maxNodes = options.maxNodes || -1; + if (maxNodes == -1) { + maxNodes = Number.MAX_VALUE; + } + + // We're going to create a few document walkers with the same filter, + // make it easier. + let filteredWalker = function(node) { + return documentWalker(node, options.whatToShow); + } + + // Need to know the first and last child. + let rawNode = node.rawNode; + let firstChild = filteredWalker(rawNode).firstChild(); + let lastChild = filteredWalker(rawNode).lastChild(); + + if (!firstChild) { + // No children, we're done. + return { hasFirst: true, hasLast: true, nodes: [] }; + } + + let start; + if (options.center) { + start = options.center.rawNode; + } else if (options.start) { + start = options.start.rawNode; + } else { + start = firstChild; + } + + let nodes = []; + + // Start by reading backward from the starting point if we're centering... + let backwardWalker = filteredWalker(start); + if (start != firstChild && options.center) { + backwardWalker.previousSibling(); + let backwardCount = Math.floor(maxNodes / 2); + let backwardNodes = this._readBackward(backwardWalker, backwardCount); + nodes = backwardNodes; + } + + // Then read forward by any slack left in the max children... + let forwardWalker = filteredWalker(start); + let forwardCount = maxNodes - nodes.length; + nodes = nodes.concat(this._readForward(forwardWalker, forwardCount)); + + // If there's any room left, it means we've run all the way to the end. + // If we're centering, check if there are more items to read at the front. + let remaining = maxNodes - nodes.length; + if (options.center && remaining > 0 && nodes[0].rawNode != firstChild) { + let firstNodes = this._readBackward(backwardWalker, remaining); + + // Then put it all back together. + nodes = firstNodes.concat(nodes); + } + + return { + hasFirst: nodes[0].rawNode == firstChild, + hasLast: nodes[nodes.length - 1].rawNode == lastChild, + nodes: nodes + }; + }, nodeArrayMethod), + + /** + * Return siblings of the given node. By default this method will return + * all siblings of the node, but there are options that can restrict this + * to a more manageable subset. + * + * If `start` or `center` are not specified, this method will center on the + * node whose siblings are requested. + * + * @param NodeActor node + * The node whose children you're curious about. + * @param object options + * Named options: + * `maxNodes`: The set of nodes returned by the method will be no longer + * than maxNodes. + * `start`: If a node is specified, the list of nodes will start + * with the given child. Mutally exclusive with `center`. + * `center`: If a node is specified, the given node will be as centered + * as possible in the list, given how close to the ends of the child + * list it is. Mutually exclusive with `start`. + * `whatToShow`: A bitmask of node types that should be included. See + * https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter. + * + * @returns an object with three items: + * hasFirst: true if the first child of the node is included in the list. + * hasLast: true if the last child of the node is included in the list. + * nodes: Child nodes returned by the request. + */ + siblings: method(function(node, options={}) { + let parentNode = documentWalker(node.rawNode).parentNode(); + if (!parentNode) { + return { + hasFirst: true, + hasLast: true, + nodes: [node] + }; + } + + if (!(options.start || options.center)) { + options.center = node; + } + + return this.children(this._ref(parentNode), options); + }, nodeArrayMethod), + + /** + * Get the next sibling of a given node. Getting nodes one at a time + * might be inefficient, be careful. + * + * @param object options + * Named options: + * `whatToShow`: A bitmask of node types that should be included. See + * https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter. + */ + nextSibling: method(function(node, options={}) { + let walker = documentWalker(node.rawNode, options.whatToShow || Ci.nsIDOMNodeFilter.SHOW_ALL); + let sibling = walker.nextSibling(); + return sibling ? this._ref(sibling) : null; + }, traversalMethod), + + /** + * Get the previous sibling of a given node. Getting nodes one at a time + * might be inefficient, be careful. + * + * @param object options + * Named options: + * `whatToShow`: A bitmask of node types that should be included. See + * https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter. + */ + previousSibling: method(function(node, options={}) { + let walker = documentWalker(node.rawNode, options.whatToShow || Ci.nsIDOMNodeFilter.SHOW_ALL); + let sibling = walker.previousSibling(); + return sibling ? this._ref(sibling) : null; + }, traversalMethod), + + /** + * Helper function for the `children` method: Read forward in the sibling + * list into an array with `count` items, including the current node. + */ + _readForward: function(walker, count) + { + let ret = []; + let node = walker.currentNode; + do { + ret.push(this._ref(node)); + node = walker.nextSibling(); + } while (node && --count); + return ret; + }, + + /** + * Helper function for the `children` method: Read backward in the sibling + * list into an array with `count` items, including the current node. + */ + _readBackward: function(walker, count) + { + let ret = []; + let node = walker.currentNode; + do { + ret.push(this._ref(node)); + node = walker.previousSibling(); + } while(node && --count); + ret.reverse(); + return ret; + }, + + /** + * Return the first node in the document that matches the given selector. + * See https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelector + * + * @param NodeActor baseNode + * @param string selector + */ + querySelector: method(function(baseNode, selector) { + let node = baseNode.rawNode.querySelector(selector); + + if (!node) { + return { + } + }; + + let node = this._ref(node); + let newParents = this.ensurePathToRoot(node); + return { + node: node, + newNodes: [parent for (parent of newParents)] + } + }, { + request: { + node: Arg(0, "domnode"), + selector: Arg(1) + }, + response: RetVal("disconnectedNode") + }), + + /** + * Return a NodeListActor with all nodes that match the given selector. + * See https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll + * + * @param NodeActor baseNode + * @param string selector + */ + querySelectorAll: method(function(baseNode, selector) { + return new NodeListActor(this, baseNode.rawNode.querySelectorAll(selector)); + }, { + request: { + node: Arg(0, "domnode"), + selector: Arg(1) + }, + response: { + list: RetVal("domnodelist") + } + }), + + /** + * Add a pseudo-class lock to a node. + * + * @param NodeActor node + * @param string pseudo + * A pseudoclass: ':hover', ':active', ':focus' + * @param options + * Options object: + * `parents`: True if the pseudo-class should be added + * to parent nodes. + * + * @returns An empty packet. A "pseudoClassLock" mutation will + * be queued for any changed nodes. + */ + addPseudoClassLock: method(function(node, pseudo, options={}) { + this._addPseudoClassLock(node, pseudo); + + if (!options.parents) { + return; + } + + let walker = documentWalker(node.rawNode); + let cur; + while ((cur = walker.parentNode())) { + let curNode = this._ref(cur); + this._addPseudoClassLock(curNode, pseudo); + } + }, { + request: { + node: Arg(0, "domnode"), + pseudoClass: Arg(1), + parents: Option(2) + }, + response: {} + }), + + _queuePseudoClassMutation: function(node) { + this.queueMutation({ + target: node.actorID, + type: "pseudoClassLock", + pseudoClassLocks: node.writePseudoClassLocks() + }); + }, + + _addPseudoClassLock: function(node, pseudo) { + if (node.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) { + return false; + } + DOMUtils.addPseudoClassLock(node.rawNode, pseudo); + this._activePseudoClassLocks.add(node); + this._queuePseudoClassMutation(node); + return true; + }, + + /** + * Remove a pseudo-class lock from a node. + * + * @param NodeActor node + * @param string pseudo + * A pseudoclass: ':hover', ':active', ':focus' + * @param options + * Options object: + * `parents`: True if the pseudo-class should be removed + * from parent nodes. + * + * @returns An empty response. "pseudoClassLock" mutations + * will be emitted for any changed nodes. + */ + removePseudoClassLock: method(function(node, pseudo, options={}) { + this._removePseudoClassLock(node, pseudo); + + if (!options.parents) { + return; + } + + let walker = documentWalker(node.rawNode); + let cur; + while ((cur = walker.parentNode())) { + let curNode = this._ref(cur); + this._removePseudoClassLock(curNode, pseudo); + } + }, { + request: { + node: Arg(0, "domnode"), + pseudoClass: Arg(1), + parents: Option(2) + }, + response: {} + }), + + _removePseudoClassLock: function(node, pseudo) { + if (node.rawNode.nodeType != Ci.nsIDOMNode.ELEMENT_NODE) { + return false; + } + DOMUtils.removePseudoClassLock(node.rawNode, pseudo); + if (!node.writePseudoClassLocks()) { + this._activePseudoClassLocks.delete(node); + } + this._queuePseudoClassMutation(node); + return true; + }, + + /** + * Clear all the pseudo-classes on a given node + * or all nodes. + */ + clearPseudoClassLocks: method(function(node) { + if (node) { + DOMUtils.clearPseudoClassLocks(node.rawNode); + this._activePseudoClassLocks.delete(node); + this._queuePseudoClassMutation(node); + } else { + for (let locked of this._activePseudoClassLocks) { + DOMUtils.clearPseudoClassLocks(locked.rawNode); + this._activePseudoClassLocks.delete(locked); + this._queuePseudoClassMutation(locked); + } + } + }, { + request: { + node: Arg(0, "domnode", { optional: true }), + }, + response: {} + }), + + /** + * Get a node's innerHTML property. + */ + innerHTML: method(function(node) { + return LongStringActor(this.conn, node.rawNode.innerHTML); + }, { + request: { + node: Arg(0, "domnode") + }, + response: { + value: RetVal("longstring") + } + }), + + /** + * Get a node's outerHTML property. + */ + outerHTML: method(function(node) { + return LongStringActor(this.conn, node.rawNode.outerHTML); + }, { + request: { + node: Arg(0, "domnode") + }, + response: { + value: RetVal("longstring") + } + }), + + /** + * Get any pending mutation records. Must be called by the client after + * the `new-mutations` notification is received. Returns an array of + * mutation records. + * + * Mutation records have a basic structure: + * + * { + * type: attributes|characterData|childList, + * target: , + * } + * + * And additional attributes based on the mutation type: + * + * `attributes` type: + * attributeName: - the attribute that changed + * attributeNamespace: - the attribute's namespace URI, if any. + * newValue: - The new value of the attribute, if any. + * + * `characterData` type: + * newValue: - the new shortValue for the node + * [incompleteValue: true] - True if the shortValue was truncated. + * + * `childList` type is returned when the set of children for a node + * has changed. Includes extra data, which can be used by the client to + * maintain its ownership subtree. + * + * added: array of - The list of actors *previously + * seen by the client* that were added to the target node. + * removed: array of The list of actors *previously + * seen by the client* that were removed from the target node. + * + * Actors that are included in a MutationRecord's `removed` but + * not in an `added` have been removed from the client's ownership + * tree (either by being moved under a node the client has seen yet + * or by being removed from the tree entirely), and is considered + * 'orphaned'. + * + * Keep in mind that if a node that the client hasn't seen is moved + * into or out of the target node, it will not be included in the + * removedNodes and addedNodes list, so if the client is interested + * in the new set of children it needs to issue a `children` request. + */ + getMutations: method(function(options={}) { + let pending = this._pendingMutations || []; + this._pendingMutations = []; + + if (options.cleanup) { + for (let node of this._orphaned) { + // Release the orphaned node. Nodes or children that have been + // retained will be moved to this._retainedOrphans. + this.releaseNode(node); + } + this._orphaned = new Set(); + } + + return pending; + }, { + request: { + cleanup: Option(0) + }, + response: { + mutations: RetVal("array:dommutation") + } + }), + + queueMutation: function(mutation) { + if (!this.actorID) { + // We've been destroyed, don't bother queueing this mutation. + return; + } + // We only send the `new-mutations` notification once, until the client + // fetches mutations with the `getMutations` packet. + let needEvent = this._pendingMutations.length === 0; + + this._pendingMutations.push(mutation); + + if (needEvent) { + events.emit(this, "new-mutations"); + } + }, + + /** + * Handles mutations from the DOM mutation observer API. + * + * @param array[MutationRecord] mutations + * See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationRecord + */ + onMutations: function(mutations) { + for (let change of mutations) { + let targetActor = this._refMap.get(change.target); + if (!targetActor) { + continue; + } + let targetNode = change.target; + let mutation = { + type: change.type, + target: targetActor.actorID, + } + + if (mutation.type === "attributes") { + mutation.attributeName = change.attributeName; + mutation.attributeNamespace = change.attributeNamespace || undefined; + mutation.newValue = targetNode.getAttribute(mutation.attributeName); + } else if (mutation.type === "characterData") { + if (targetNode.nodeValue.length > gValueSummaryLength) { + mutation.newValue = targetNode.nodeValue.substring(0, gValueSummaryLength); + mutation.incompleteValue = true; + } else { + mutation.newValue = targetNode.nodeValue; + } + } else if (mutation.type === "childList") { + // Get the list of removed and added actors that the client has seen + // so that it can keep its ownership tree up to date. + let removedActors = []; + let addedActors = []; + for (let removed of change.removedNodes) { + let removedActor = this._refMap.get(removed); + if (!removedActor) { + // If the client never encountered this actor we don't need to + // mention that it was removed. + continue; + } + // While removed from the tree, nodes are saved as orphaned. + this._orphaned.add(removedActor); + removedActors.push(removedActor.actorID); + } + for (let added of change.addedNodes) { + let addedActor = this._refMap.get(added); + if (!addedActor) { + // If the client never encounted this actor we don't need to tell + // it about its addition for ownership tree purposes - if the + // client wants to see the new nodes it can ask for children. + continue; + } + // The actor is reconnected to the ownership tree, unorphan + // it and let the client know so that its ownership tree is up + // to date. + this._orphaned.delete(addedActor); + addedActors.push(addedActor.actorID); + } + mutation.numChildren = change.target.childNodes.length; + mutation.removed = removedActors; + mutation.added = addedActors; + } + this.queueMutation(mutation); + } + }, + + onFrameLoad: function(window) { + let frame = window.frameElement; + let frameActor = this._refMap.get(frame); + if (!frameActor) { + return; + } + + this.queueMutation({ + type: "frameLoad", + target: frameActor.actorID, + }); + + // Send a childList mutation on the frame. + this.queueMutation({ + type: "childList", + target: frameActor.actorID, + added: [], + removed: [] + }) + }, + + // Returns true if domNode is in window or a subframe. + _childOfWindow: function(window, domNode) { + let win = nodeDocument(domNode).defaultView; + while (win) { + if (win === window) { + return true; + } + win = win.frameElement; + } + return false; + }, + + onFrameUnload: function(window) { + // Any retained orphans that belong to this document + // or its children need to be released, and a mutation sent + // to notify of that. + let releasedOrphans = []; + + for (let retained of this._retainedOrphans) { + if (Cu.isDeadWrapper(retained.rawNode) || + this._childOfWindow(window, retained.rawNode)) { + this._retainedOrphans.delete(retained); + releasedOrphans.push(retained.actorID); + this.releaseNode(retained, { force: true }); + } + } + + if (releasedOrphans.length > 0) { + this.queueMutation({ + target: this.rootNode.actorID, + type: "unretained", + nodes: releasedOrphans + }); + } + + let doc = window.document; + let documentActor = this._refMap.get(doc); + if (!documentActor) { + return; + } + + this.queueMutation({ + type: "documentUnload", + target: documentActor.actorID + }); + + let walker = documentWalker(doc); + let parentNode = walker.parentNode(); + if (parentNode) { + // Send a childList mutation on the frame so that clients know + // they should reread the children list. + this.queueMutation({ + type: "childList", + target: this._refMap.get(parentNode).actorID, + added: [], + removed: [] + }); + } + + // Need to force a release of this node, because those nodes can't + // be accessed anymore. + this.releaseNode(documentActor, { force: true }); + } +}); + +/** + * Client side of the DOM walker. + */ +var WalkerFront = exports.WalkerFront = protocol.FrontClass(WalkerActor, { + // Set to true if cleanup should be requested after every mutation list. + autoCleanup: true, + + initialize: function(client, form) { + protocol.Front.prototype.initialize.call(this, client, form); + this._orphaned = new Set(); + this._retainedOrphans = new Set(); + }, + + destroy: function() { + protocol.Front.prototype.destroy.call(this); + }, + + // Update the object given a form representation off the wire. + form: function(json) { + this.actorID = json.actorID; + this.rootNode = types.getType("domnode").read(json.root, this); + }, + + /** + * When reading an actor form off the wire, we want to hook it up to its + * parent front. The protocol guarantees that the parent will be seen + * by the client in either a previous or the current request. + * So if we've already seen this parent return it, otherwise create + * a bare-bones stand-in node. The stand-in node will be updated + * with a real form by the end of the deserialization. + */ + ensureParentFront: function(id) { + let front = this.get(id); + if (front) { + return front; + } + + return types.getType("domnode").read({ actor: id }, this, "standin"); + }, + + /** + * See the documentation for WalkerActor.prototype.retainNode for + * information on retained nodes. + * + * From the client's perspective, `retainNode` can fail if the node in + * question is removed from the ownership tree before the `retainNode` + * request reaches the server. This can only happen if the client has + * asked the server to release nodes but hasn't gotten a response + * yet: Either a `releaseNode` request or a `getMutations` with `cleanup` + * set is outstanding. + * + * If either of those requests is outstanding AND releases the retained + * node, this request will fail with noSuchActor, but the ownership tree + * will stay in a consistent state. + * + * Because the protocol guarantees that requests will be processed and + * responses received in the order they were sent, we get the right + * semantics by setting our local retained flag on the node only AFTER + * a SUCCESSFUL retainNode call. + */ + retainNode: protocol.custom(function(node) { + return this._retainNode(node).then(() => { + node.retained = true; + }); + }, { + impl: "_retainNode", + }), + + unretainNode: protocol.custom(function(node) { + return this._unretainNode(node).then(() => { + node.retained = false; + if (this._retainedOrphans.has(node)) { + this._retainedOrphans.delete(node); + this._releaseFront(node); + } + }); + }, { + impl: "_unretainNode" + }), + + releaseNode: protocol.custom(function(node, options={}) { + // NodeFront.destroy will destroy children in the ownership tree too, + // mimicking what the server will do here. + let actorID = node.actorID; + this._releaseFront(node, !!options.force); + return this._releaseNode({ actorID: actorID }); + }, { + impl: "_releaseNode" + }), + + querySelector: protocol.custom(function(queryNode, selector) { + return this._querySelector(queryNode, selector).then(response => { + return response.node; + }); + }, { + impl: "_querySelector" + }), + + _releaseFront: function(node, force) { + if (node.retained && !force) { + node.reparent(null); + this._retainedOrphans.add(node); + return; + } + + if (node.retained) { + // Forcing a removal. + this._retainedOrphans.delete(node); + } + + // Release any children + for (let child of node.treeChildren()) { + this._releaseFront(child, force); + } + + // All children will have been removed from the node by this point. + node.reparent(null); + node.destroy(); + }, + + /** + * Get any unprocessed mutation records and process them. + */ + getMutations: protocol.custom(function(options={}) { + return this._getMutations(options).then(mutations => { + let emitMutations = []; + for (let change of mutations) { + // The target is only an actorID, get the associated front. + let targetID = change.target; + let targetFront = this.get(targetID); + if (!targetFront) { + console.trace("Got a mutation for an unexpected actor: " + targetID + ", please file a bug on bugzilla.mozilla.org!"); + continue; + } + + let emittedMutation = object.merge(change, { target: targetFront }); + + if (change.type === "childList") { + // Update the ownership tree according to the mutation record. + let addedFronts = []; + let removedFronts = []; + for (let removed of change.removed) { + let removedFront = this.get(removed); + if (!removedFront) { + console.error("Got a removal of an actor we didn't know about: " + removed); + continue; + } + // Remove from the ownership tree + removedFront.reparent(null); + + // This node is orphaned unless we get it in the 'added' list + // eventually. + this._orphaned.add(removedFront); + removedFronts.push(removedFront); + } + for (let added of change.added) { + let addedFront = this.get(added); + if (!addedFront) { + console.error("Got an addition of an actor we didn't know about: " + added); + continue; + } + addedFront.reparent(targetFront) + + // The actor is reconnected to the ownership tree, unorphan + // it. + this._orphaned.delete(addedFront); + addedFronts.push(addedFront); + } + // Before passing to users, replace the added and removed actor + // ids with front in the mutation record. + emittedMutation.added = addedFronts; + emittedMutation.removed = removedFronts; + targetFront._form.numChildren = change.numChildren; + } else if (change.type === "frameLoad") { + // Nothing we need to do here, except verify that we don't have any + // document children, because we should have gotten a documentUnload + // first. + for (let child of targetFront.treeChildren()) { + if (child.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) { + console.trace("Got an unexpected frameLoad in the inspector, please file a bug on bugzilla.mozilla.org!"); + } + } + } else if (change.type === "documentUnload") { + // We try to give fronts instead of actorIDs, but these fronts need + // to be destroyed now. + emittedMutation.target = targetFront.actorID; + emittedMutation.targetParent = targetFront.parentNode(); + + // Release the document node and all of its children, even retained. + this._releaseFront(targetFront, true); + } else if (change.type === "unretained") { + // Retained orphans were force-released without the intervention of + // client (probably a navigated frame). + for (let released of change.nodes) { + let releasedFront = this.get(released); + this._retainedOrphans.delete(released); + this._releaseFront(releasedFront, true); + } + } else { + targetFront.updateMutation(change); + } + + emitMutations.push(emittedMutation); + } + + if (options.cleanup) { + for (let node of this._orphaned) { + // This will move retained nodes to this._retainedOrphans. + this._releaseFront(node); + } + this._orphaned = new Set(); + } + + events.emit(this, "mutations", emitMutations); + }); + }, { + impl: "_getMutations" + }), + + /** + * Handle the `new-mutations` notification by fetching the + * available mutation records. + */ + onMutations: protocol.preEvent("new-mutations", function() { + // Fetch and process the mutations. + this.getMutations({cleanup: this.autoCleanup}).then(null, console.error); + }), + + isLocal: function() { + return !!this.conn._transport._serverConnection; + }, + + // XXX hack during transition to remote inspector: get a proper NodeFront + // for a given local node. Only works locally. + frontForRawNode: function(rawNode){ + if (!this.isLocal()) { + console.warn("Tried to use frontForRawNode on a remote connection."); + return null; + } + let walkerActor = this.conn._transport._serverConnection.getActor(this.actorID); + if (!walkerActor) { + throw Error("Could not find client side for actor " + this.actorID); + } + let nodeActor = walkerActor._ref(rawNode); + + // Pass the node through a read/write pair to create the client side actor. + let nodeType = types.getType("domnode"); + let returnNode = nodeType.read(nodeType.write(nodeActor, walkerActor), this); + let top = returnNode; + let extras = walkerActor.parents(nodeActor); + for (let extraActor of extras) { + top = nodeType.read(nodeType.write(extraActor, walkerActor), this); + } + + if (top !== this.rootNode) { + // Imported an already-orphaned node. + this._orphaned.add(top); + walkerActor._orphaned.add(this.conn._transport._serverConnection.getActor(top.actorID)); + } + return returnNode; + } +}); + +/** + * Convenience API for building a list of attribute modifications + * for the `modifyAttributes` request. + */ +var AttributeModificationList = Class({ + initialize: function(node) { + this.node = node; + this.modifications = []; + }, + + apply: function() { + let ret = this.node.modifyAttributes(this.modifications); + return ret; + }, + + destroy: function() { + this.node = null; + this.modification = null; + }, + + setAttributeNS: function(ns, name, value) { + this.modifications.push({ + attributeNamespace: ns, + attributeName: name, + newValue: value + }); + }, + + setAttribute: function(name, value) { + this.setAttributeNS(undefined, name, value); + }, + + removeAttributeNS: function(ns, name) { + this.setAttributeNS(ns, name, undefined); + }, + + removeAttribute: function(name) { + this.setAttributeNS(undefined, name, undefined); + } +}) + +/** + * Server side of the inspector actor, which is used to create + * inspector-related actors, including the walker. + */ +var InspectorActor = protocol.ActorClass({ + typeName: "inspector", + initialize: function(conn, tabActor) { + protocol.Actor.prototype.initialize.call(this, conn); + this.tabActor = tabActor; + }, + + get window() { + let tabActor = this.tabActor; + if (tabActor.browser instanceof Ci.nsIDOMWindow) { + return tabActor.browser; + } else if (tabActor.browser instanceof Ci.nsIDOMElement) { + return tabActor.browser.contentWindow; + } + return null; + }, + + getWalker: method(function(options={}) { + let deferred = promise.defer(); + + let window = this.window; + + var domReady = () => { + let tabActor = this.tabActor; + window.removeEventListener("DOMContentLoaded", domReady, true); + deferred.resolve(WalkerActor(this.conn, window.document, tabActor._tabbrowser, options)); + }; + + if (window.document.readyState === "loading") { + window.addEventListener("DOMContentLoaded", domReady, true); + } else { + domReady(); + } + + return deferred.promise; + }, { + request: {}, + response: { + walker: RetVal("domwalker") + } + }) +}); + +/** + * Client side of the inspector actor, which is used to create + * inspector-related actors, including the walker. + */ +var InspectorFront = exports.InspectorFront = protocol.FrontClass(InspectorActor, { + initialize: function(client, tabForm) { + protocol.Front.prototype.initialize.call(this, client); + this.actorID = tabForm.inspectorActor; + + // XXX: This is the first actor type in its hierarchy to use the protocol + // library, so we're going to self-own on the client side for now. + client.addActorPool(this); + this.manage(this); + } +}); + +function documentWalker(node, whatToShow=Ci.nsIDOMNodeFilter.SHOW_ALL) { + return new DocumentWalker(node, whatToShow, whitespaceTextFilter, false); +} + +// Exported for test purposes. +exports._documentWalker = documentWalker; + +function nodeDocument(node) { + return node.ownerDocument || (node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null); +} + +/** + * Similar to a TreeWalker, except will dig in to iframes and it doesn't + * implement the good methods like previousNode and nextNode. + * + * See TreeWalker documentation for explanations of the methods. + */ +function DocumentWalker(aNode, aShow, aFilter, aExpandEntityReferences) +{ + let doc = nodeDocument(aNode); + this.walker = doc.createTreeWalker(nodeDocument(aNode), + aShow, aFilter, aExpandEntityReferences); + this.walker.currentNode = aNode; + this.filter = aFilter; +} + +DocumentWalker.prototype = { + get node() this.walker.node, + get whatToShow() this.walker.whatToShow, + get expandEntityReferences() this.walker.expandEntityReferences, + get currentNode() this.walker.currentNode, + set currentNode(aVal) this.walker.currentNode = aVal, + + /** + * Called when the new node is in a different document than + * the current node, creates a new treewalker for the document we've + * run in to. + */ + _reparentWalker: function DW_reparentWalker(aNewNode) { + if (!aNewNode) { + return null; + } + let doc = nodeDocument(aNewNode); + let walker = doc.createTreeWalker(doc, + this.whatToShow, this.filter, this.expandEntityReferences); + walker.currentNode = aNewNode; + this.walker = walker; + return aNewNode; + }, + + parentNode: function DW_parentNode() + { + let currentNode = this.walker.currentNode; + let parentNode = this.walker.parentNode(); + + if (!parentNode) { + if (currentNode && currentNode.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE + && currentNode.defaultView) { + let embeddingFrame = currentNode.defaultView.frameElement; + if (embeddingFrame) { + return this._reparentWalker(embeddingFrame); + } + } + return null; + } + + return parentNode; + }, + + firstChild: function DW_firstChild() + { + let node = this.walker.currentNode; + if (!node) + return null; + if (node.contentDocument) { + return this._reparentWalker(node.contentDocument); + } else if (node.getSVGDocument) { + return this._reparentWalker(node.getSVGDocument()); + } + return this.walker.firstChild(); + }, + + lastChild: function DW_lastChild() + { + let node = this.walker.currentNode; + if (!node) + return null; + if (node.contentDocument) { + return this._reparentWalker(node.contentDocument); + } else if (node.getSVGDocument) { + return this._reparentWalker(node.getSVGDocument()); + } + return this.walker.lastChild(); + }, + + previousSibling: function DW_previousSibling() this.walker.previousSibling(), + nextSibling: function DW_nextSibling() this.walker.nextSibling() +} + +/** + * A tree walker filter for avoiding empty whitespace text nodes. + */ +function whitespaceTextFilter(aNode) +{ + if (aNode.nodeType == Ci.nsIDOMNode.TEXT_NODE && + !/[^\s]/.exec(aNode.nodeValue)) { + return Ci.nsIDOMNodeFilter.FILTER_SKIP; + } else { + return Ci.nsIDOMNodeFilter.FILTER_ACCEPT; + } +} + +loader.lazyGetter(this, "DOMUtils", function () { + return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); +}); diff --git a/scripting/javascript/bindings/js/debugger/actors/profiler.js b/scripting/javascript/bindings/js/debugger/actors/profiler.js new file mode 100644 index 0000000000..bc87f48599 --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/profiler.js @@ -0,0 +1,218 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var startedProfilers = 0; +var startTime = 0; + +function getCurrentTime() { + return (new Date()).getTime() - startTime; +} + +/** + * Creates a ProfilerActor. ProfilerActor provides remote access to the + * built-in profiler module. + */ +function ProfilerActor(aConnection) +{ + this._profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler); + this._started = false; + this._observedEvents = []; +} + +ProfilerActor.prototype = { + actorPrefix: "profiler", + + disconnect: function() { + for (var event of this._observedEvents) { + Services.obs.removeObserver(this, event); + } + + this.stopProfiler(); + this._profiler = null; + }, + + stopProfiler: function() { + // We stop the profiler only after the last client has + // stopped profiling. Otherwise there's a problem where + // we stop the profiler as soon as you close the devtools + // panel in one tab even though there might be other + // profiler instances running in other tabs. + if (!this._started) { + return; + } + this._started = false; + startedProfilers -= 1; + if (startedProfilers <= 0) { + this._profiler.StopProfiler(); + } + }, + + onStartProfiler: function(aRequest) { + this._profiler.StartProfiler(aRequest.entries, aRequest.interval, + aRequest.features, aRequest.features.length); + this._started = true; + startedProfilers += 1; + startTime = (new Date()).getTime(); + return { "msg": "profiler started" } + }, + onStopProfiler: function(aRequest) { + this.stopProfiler(); + return { "msg": "profiler stopped" } + }, + onGetProfileStr: function(aRequest) { + var profileStr = this._profiler.GetProfile(); + return { "profileStr": profileStr } + }, + onGetProfile: function(aRequest) { + var profile = this._profiler.getProfileData(); + return { "profile": profile, "currentTime": getCurrentTime() } + }, + onIsActive: function(aRequest) { + var isActive = this._profiler.IsActive(); + var currentTime = isActive ? getCurrentTime() : null; + return { "isActive": isActive, "currentTime": currentTime } + }, + onGetResponsivenessTimes: function(aRequest) { + var times = this._profiler.GetResponsivenessTimes({}); + return { "responsivenessTimes": times } + }, + onGetFeatures: function(aRequest) { + var features = this._profiler.GetFeatures([]); + return { "features": features } + }, + onGetSharedLibraryInformation: function(aRequest) { + var sharedLibraries = this._profiler.getSharedLibraryInformation(); + return { "sharedLibraryInformation": sharedLibraries } + }, + onRegisterEventNotifications: function(aRequest) { + let registered = []; + for (var event of aRequest.events) { + if (this._observedEvents.indexOf(event) != -1) + continue; + Services.obs.addObserver(this, event, false); + this._observedEvents.push(event); + registered.push(event); + } + return { registered: registered } + }, + onUnregisterEventNotifications: function(aRequest) { + let unregistered = []; + for (var event of aRequest.events) { + let idx = this._observedEvents.indexOf(event); + if (idx == -1) + continue; + Services.obs.removeObserver(this, event); + this._observedEvents.splice(idx, 1); + unregistered.push(event); + } + return { unregistered: unregistered } + }, + observe: makeInfallible(function(aSubject, aTopic, aData) { + /* + * this.conn.send can only transmit acyclic values. However, it is + * idiomatic for wrapped JS objects like aSubject (and possibly aData?) + * to have a 'wrappedJSObject' property pointing to themselves. + * + * this.conn.send also assumes that it can retain the object it is + * passed to be handled on later event ticks; and that it's okay to + * freeze it. Since we don't really know what aSubject and aData are, + * we need to pass this.conn.send a copy of them, not the originals. + * + * We break the cycle and make the copy by JSON.stringifying those + * values with a replacer that omits properties known to introduce + * cycles, and then JSON.parsing the result. This spends processor + * time, but it's simple. + */ + function cycleBreaker(key, value) { + if (key === 'wrappedJSObject') { + return undefined; + } + return value; + } + + /* + * If these values are objects with a non-null 'wrappedJSObject' + * property, use its value. Otherwise, use the value unchanged. + */ + aSubject = (aSubject && aSubject.wrappedJSObject) || aSubject; + aData = (aData && aData.wrappedJSObject) || aData; + + let subj = JSON.parse(JSON.stringify(aSubject, cycleBreaker)); + let data = JSON.parse(JSON.stringify(aData, cycleBreaker)); + + let send = (extra) => { + data = data || {}; + + if (extra) + data.extra = extra; + + this.conn.send({ + from: this.actorID, + type: "eventNotification", + event: aTopic, + subject: subj, + data: data + }); + } + + if (aTopic !== "console-api-profiler") + return void send(); + + // If the event was generated from console.profile or + // console.profileEnd we need to start the profiler + // right away and only then notify our client. Otherwise, + // we'll lose precious samples. + + let name = subj.arguments[0]; + + if (subj.action === "profile") { + let resp = this.onIsActive(); + + if (resp.isActive) { + return void send({ + name: name, + currentTime: resp.currentTime, + action: "profile" + }); + } + + this.onStartProfiler({ + entries: 1000000, + interval: 1, + features: ["js"] + }); + + return void send({ currentTime: 0, action: "profile", name: name }); + } + + if (subj.action === "profileEnd") { + let resp = this.onGetProfile(); + resp.action = "profileEnd"; + resp.name = name; + send(resp); + } + + return undefined; // Otherwise xpcshell tests fail. + }, "ProfilerActor.prototype.observe"), +}; + +/** + * The request types this actor can handle. + */ +ProfilerActor.prototype.requestTypes = { + "startProfiler": ProfilerActor.prototype.onStartProfiler, + "stopProfiler": ProfilerActor.prototype.onStopProfiler, + "getProfileStr": ProfilerActor.prototype.onGetProfileStr, + "getProfile": ProfilerActor.prototype.onGetProfile, + "isActive": ProfilerActor.prototype.onIsActive, + "getResponsivenessTimes": ProfilerActor.prototype.onGetResponsivenessTimes, + "getFeatures": ProfilerActor.prototype.onGetFeatures, + "getSharedLibraryInformation": ProfilerActor.prototype.onGetSharedLibraryInformation, + "registerEventNotifications": ProfilerActor.prototype.onRegisterEventNotifications, + "unregisterEventNotifications": ProfilerActor.prototype.onUnregisterEventNotifications +}; + +DebuggerServer.addGlobalActor(ProfilerActor, "profilerActor"); diff --git a/scripting/javascript/bindings/js/debugger/actors/root.js b/scripting/javascript/bindings/js/debugger/actors/root.js new file mode 100644 index 0000000000..aa0d85342b --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/root.js @@ -0,0 +1,329 @@ +/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/* Root actor for the remote debugging protocol. */ + +/** + * Methods shared between RootActor and BrowserTabActor. + */ + +/** + * Populate |this._extraActors| as specified by |aFactories|, reusing whatever + * actors are already there. Add all actors in the final extra actors table to + * |aPool|. + * + * The root actor and the tab actor use this to instantiate actors that other + * parts of the browser have specified with DebuggerServer.addTabActor antd + * DebuggerServer.addGlobalActor. + * + * @param aFactories + * An object whose own property names are the names of properties to add to + * some reply packet (say, a tab actor grip or the "listTabs" response + * form), and whose own property values are actor constructor functions, as + * documented for addTabActor and addGlobalActor. + * + * @param this + * The BrowserRootActor or BrowserTabActor with which the new actors will + * be associated. It should support whatever API the |aFactories| + * constructor functions might be interested in, as it is passed to them. + * For the sake of CommonCreateExtraActors itself, it should have at least + * the following properties: + * + * - _extraActors + * An object whose own property names are factory table (and packet) + * property names, and whose values are no-argument actor constructors, + * of the sort that one can add to an ActorPool. + * + * - conn + * The DebuggerServerConnection in which the new actors will participate. + * + * - actorID + * The actor's name, for use as the new actors' parentID. + */ +function CommonCreateExtraActors(aFactories, aPool) { + // Walk over global actors added by extensions. + for (let name in aFactories) { + let actor = this._extraActors[name]; + if (!actor) { + actor = aFactories[name].bind(null, this.conn, this); + actor.prototype = aFactories[name].prototype; + actor.parentID = this.actorID; + this._extraActors[name] = actor; + } + aPool.addActor(actor); + } +} + +/** + * Append the extra actors in |this._extraActors|, constructed by a prior call + * to CommonCreateExtraActors, to |aObject|. + * + * @param aObject + * The object to which the extra actors should be added, under the + * property names given in the |aFactories| table passed to + * CommonCreateExtraActors. + * + * @param this + * The BrowserRootActor or BrowserTabActor whose |_extraActors| table we + * should use; see above. + */ +function CommonAppendExtraActors(aObject) { + for (let name in this._extraActors) { + let actor = this._extraActors[name]; + aObject[name] = actor.actorID; + } +} + +/** + * Create a remote debugging protocol root actor. + * + * @param aConnection + * The DebuggerServerConnection whose root actor we are constructing. + * + * @param aParameters + * The properties of |aParameters| provide backing objects for the root + * actor's requests; if a given property is omitted from |aParameters|, the + * root actor won't implement the corresponding requests or notifications. + * Supported properties: + * + * - tabList: a live list (see below) of tab actors. If present, the + * new root actor supports the 'listTabs' request, providing the live + * list's elements as its tab actors, and sending 'tabListChanged' + * notifications when the live list's contents change. One actor in + * this list must have a true '.selected' property. + * + * - globalActorFactories: an object |A| describing further actors to + * attach to the 'listTabs' reply. This is the type accumulated by + * DebuggerServer.addGlobalActor. For each own property |P| of |A|, + * the root actor adds a property named |P| to the 'listTabs' + * reply whose value is the name of an actor constructed by + * |A[P]|. + * + * - onShutdown: a function to call when the root actor is disconnected. + * + * Instance properties: + * + * - applicationType: the string the root actor will include as the + * "applicationType" property in the greeting packet. By default, this + * is "browser". + * + * Live lists: + * + * A "live list", as used for the |tabList|, is an object that presents a + * list of actors, and also notifies its clients of changes to the list. A + * live list's interface is two properties: + * + * - iterator: a method that returns an iterator. A for-of loop will call + * this method to obtain an iterator for the loop, so if LL is + * a live list, one can simply write 'for (i of LL) ...'. + * + * - onListChanged: a handler called, with no arguments, when the set of + * values the iterator would produce has changed since the last + * time 'iterator' was called. This may only be set to null or a + * callable value (one for which the typeof operator returns + * 'function'). (Note that the live list will not call the + * onListChanged handler until the list has been iterated over + * once; if nobody's seen the list in the first place, nobody + * should care if its contents have changed!) + * + * When the list changes, the list implementation should ensure that any + * actors yielded in previous iterations whose referents (tabs) still exist + * get yielded again in subsequent iterations. If the underlying referent + * is the same, the same actor should be presented for it. + * + * The root actor registers an 'onListChanged' handler on the appropriate + * list when it may need to send the client 'tabListChanged' notifications, + * and is careful to remove the handler whenever it does not need to send + * such notifications (including when it is disconnected). This means that + * live list implementations can use the state of the handler property (set + * or null) to install and remove observers and event listeners. + * + * Note that, as the only way for the root actor to see the members of the + * live list is to begin an iteration over the list, the live list need not + * actually produce any actors until they are reached in the course of + * iteration: alliterative lazy live lists. + */ +function RootActor(aConnection, aParameters) { + this.conn = aConnection; + this._parameters = aParameters; + this._onTabListChanged = this.onTabListChanged.bind(this); + this._extraActors = {}; +} + +RootActor.prototype = { + constructor: RootActor, + applicationType: "browser", + + /** + * Return a 'hello' packet as specified by the Remote Debugging Protocol. + */ + sayHello: function() { + return { + from: "root", + applicationType: this.applicationType, + /* This is not in the spec, but it's used by tests. */ + testConnectionPrefix: this.conn.prefix, + traits: { + sources: true + } + }; + }, + + /** + * Disconnects the actor from the browser window. + */ + disconnect: function() { + /* Tell the live lists we aren't watching any more. */ + if (this._parameters.tabList) { + this._parameters.tabList.onListChanged = null; + } + if (typeof this._parameters.onShutdown === 'function') { + this._parameters.onShutdown(); + } + this._extraActors = null; + }, + + /* The 'listTabs' request and the 'tabListChanged' notification. */ + + /** + * Handles the listTabs request. The actors will survive until at least + * the next listTabs request. + */ + onListTabs: function() { + + let tabList = this._parameters.tabList; + if (!tabList) { + return { from: "root", error: "noTabs", + message: "This root actor has no browser tabs." }; + } + + /* + * Walk the tab list, accumulating the array of tab actors for the + * reply, and moving all the actors to a new ActorPool. We'll + * replace the old tab actor pool with the one we build here, thus + * retiring any actors that didn't get listed again, and preparing any + * new actors to receive packets. + */ + let newActorPool = new ActorPool(this.conn); + let tabActorList = []; + let selected; + for (let tabActor of tabList) { + if (tabActor.selected) { + selected = tabActorList.length; + } + tabActor.parentID = this.actorID; + newActorPool.addActor(tabActor); + tabActorList.push(tabActor); + } + + /* DebuggerServer.addGlobalActor support: create actors. */ + this._createExtraActors(this._parameters.globalActorFactories, newActorPool); + + /* + * Drop the old actorID -> actor map. Actors that still mattered were + * added to the new map; others will go away. + */ + if (this._tabActorPool) { + this.conn.removeActorPool(this._tabActorPool); + } + this._tabActorPool = newActorPool; + this.conn.addActorPool(this._tabActorPool); + + let reply = { + "from": "root", + "selected": selected || 0, + "tabs": [actor.grip() for (actor of tabActorList)] + }; + + /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */ + this._appendExtraActors(reply); + + /* + * Now that we're actually going to report the contents of tabList to + * the client, we're responsible for letting the client know if it + * changes. + */ + tabList.onListChanged = this._onTabListChanged; + + return reply; + }, + + onTabListChanged: function () { + this.conn.send({ from:"root", type:"tabListChanged" }); + /* It's a one-shot notification; no need to watch any more. */ + this._parameters.tabList.onListChanged = null; + }, + + /* This is not in the spec, but it's used by tests. */ + onEcho: (aRequest) => aRequest, + + /* Support for DebuggerServer.addGlobalActor. */ + _createExtraActors: CommonCreateExtraActors, + _appendExtraActors: CommonAppendExtraActors, + + /* ThreadActor hooks. */ + + /** + * Prepare to enter a nested event loop by disabling debuggee events. + */ + preNest: function() { + // Disable events in all open windows. + let e = windowMediator.getEnumerator(null); + while (e.hasMoreElements()) { + let win = e.getNext(); + let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.suppressEventHandling(true); + windowUtils.suspendTimeouts(); + } + }, + + /** + * Prepare to exit a nested event loop by enabling debuggee events. + */ + postNest: function(aNestData) { + // Enable events in all open windows. + let e = windowMediator.getEnumerator(null); + while (e.hasMoreElements()) { + let win = e.getNext(); + let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.resumeTimeouts(); + windowUtils.suppressEventHandling(false); + } + }, + + /* ChromeDebuggerActor hooks. */ + + /** + * Add the specified actor to the default actor pool connection, in order to + * keep it alive as long as the server is. This is used by breakpoints in the + * thread and chrome debugger actors. + * + * @param actor aActor + * The actor object. + */ + addToParentPool: function(aActor) { + this.conn.addActor(aActor); + }, + + /** + * Remove the specified actor from the default actor pool. + * + * @param BreakpointActor aActor + * The actor object. + */ + removeFromParentPool: function(aActor) { + this.conn.removeActor(aActor); + } +} + +RootActor.prototype.requestTypes = { + "listTabs": RootActor.prototype.onListTabs, + "echo": RootActor.prototype.onEcho +}; diff --git a/scripting/javascript/bindings/js/debugger/actors/script.js b/scripting/javascript/bindings/js/debugger/actors/script.js new file mode 100644 index 0000000000..2e65052e29 --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/script.js @@ -0,0 +1,2946 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; js-indent-level: 2; -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * JSD2 actors. + */ +/** + * Creates a ThreadActor. + * + * ThreadActors manage a JSInspector object and manage execution/inspection + * of debuggees. + * + * @param aHooks object + * An object with preNest and postNest methods for calling when entering + * and exiting a nested event loop, addToParentPool and + * removeFromParentPool methods for handling the lifetime of actors that + * will outlive the thread, like breakpoints. + * @param aGlobal object [optional] + * An optional (for content debugging only) reference to the content + * window. + */ +function ThreadActor(aHooks, aGlobal) +{ + this._state = "detached"; + this._frameActors = []; + this._environmentActors = []; + this._hooks = aHooks; + this.global = aGlobal; + + this.findGlobals = this.globalManager.findGlobals.bind(this); + this.onNewGlobal = this.globalManager.onNewGlobal.bind(this); + this.onNewSource = this.onNewSource.bind(this); + + this._options = { + useSourceMaps: false + }; +} + +/** + * The breakpoint store must be shared across instances of ThreadActor so that + * page reloads don't blow away all of our breakpoints. + */ +ThreadActor._breakpointStore = {}; + +ThreadActor.prototype = { + actorPrefix: "context", + + get state() { return this._state; }, + get attached() this.state == "attached" || + this.state == "running" || + this.state == "paused", + + get _breakpointStore() { return ThreadActor._breakpointStore; }, + + get threadLifetimePool() { + if (!this._threadLifetimePool) { + this._threadLifetimePool = new ActorPool(this.conn); + this.conn.addActorPool(this._threadLifetimePool); + this._threadLifetimePool.objectActors = new WeakMap(); + } + return this._threadLifetimePool; + }, + + get sources() { + if (!this._sources) { + this._sources = new ThreadSources(this, this._options.useSourceMaps, + this._allowSource, this.onNewSource); + } + return this._sources; + }, + + clearDebuggees: function TA_clearDebuggees() { + if (this.dbg) { + this.dbg.removeAllDebuggees(); + } + this.conn.removeActorPool(this._threadLifetimePool || undefined); + this._threadLifetimePool = null; + this._sources = null; + }, + + /** + * Add a debuggee global to the Debugger object. + */ + addDebuggee: function TA_addDebuggee(aGlobal) { + try { + this.dbg.addDebuggee(aGlobal); + } catch (e) { + // Ignore attempts to add the debugger's compartment as a debuggee. + dumpn("Ignoring request to add the debugger's compartment as a debuggee"); + } + }, + + /** + * Initialize the Debugger. + */ + _initDebugger: function TA__initDebugger() { + this.dbg = new Debugger(); + this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this); + this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this); + this.dbg.onNewScript = this.onNewScript.bind(this); + this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this); + // Keep the debugger disabled until a client attaches. + this.dbg.enabled = this._state != "detached"; + }, + + /** + * Remove a debuggee global from the JSInspector. + */ + removeDebugee: function TA_removeDebuggee(aGlobal) { + try { + this.dbg.removeDebuggee(aGlobal); + } catch(ex) { + // XXX: This debuggee has code currently executing on the stack, + // we need to save this for later. + } + }, + + /** + * Add the provided window and all windows in its frame tree as debuggees. + */ + _addDebuggees: function TA__addDebuggees(aWindow) { + this.addDebuggee(aWindow); + let frames = aWindow.frames; + if (frames) { + for (let i = 0; i < frames.length; i++) { + this._addDebuggees(frames[i]); + } + } + }, + + /** + * An object that will be used by ThreadActors to tailor their behavior + * depending on the debugging context being required (chrome or content). + */ + globalManager: { + findGlobals: function TA_findGlobals() { + this._addDebuggees(this.global); + }, + + /** + * A function that the engine calls when a new global object has been + * created. + * + * @param aGlobal Debugger.Object + * The new global object that was created. + */ + onNewGlobal: function TA_onNewGlobal(aGlobal) { + // Content debugging only cares about new globals in the contant window, + // like iframe children. + if (aGlobal.hostAnnotations && + aGlobal.hostAnnotations.type == "document" && + aGlobal.hostAnnotations.element === this.global) { + this.addDebuggee(aGlobal); + // Notify the client. + this.conn.send({ + from: this.actorID, + type: "newGlobal", + // TODO: after bug 801084 lands see if we need to JSONify this. + hostAnnotations: aGlobal.hostAnnotations + }); + } + } + }, + + disconnect: function TA_disconnect() { + dumpn("in ThreadActor.prototype.disconnect"); + if (this._state == "paused") { + this.onResume(); + } + + this._state = "exited"; + + this.clearDebuggees(); + + if (!this.dbg) { + return; + } + this.dbg.enabled = false; + this.dbg = null; + }, + + /** + * Disconnect the debugger and put the actor in the exited state. + */ + exit: function TA_exit() { + this.disconnect(); + }, + + // Request handlers + onAttach: function TA_onAttach(aRequest) { + if (this.state === "exited") { + return { type: "exited" }; + } + + if (this.state !== "detached") { + return { error: "wrongState" }; + } + + this._state = "attached"; + + update(this._options, aRequest.options || {}); + + if (!this.dbg) { + this._initDebugger(); + } + this.findGlobals(); + this.dbg.enabled = true; + try { + // Put ourselves in the paused state. + let packet = this._paused(); + if (!packet) { + return { error: "notAttached" }; + } + packet.why = { type: "attached" }; + + this._restoreBreakpoints(); + + // Send the response to the attach request now (rather than + // returning it), because we're going to start a nested event loop + // here. + this.conn.send(packet); + + // Start a nested event loop. + this._nest(); + + // We already sent a response to this request, don't send one + // now. + return null; + } catch (e) { + reportError(e); + return { error: "notAttached", message: e.toString() }; + } + }, + + onDetach: function TA_onDetach(aRequest) { + this.disconnect(); + dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet"); + return { + type: "detached" + }; + }, + + onReconfigure: function TA_onReconfigure(aRequest) { + if (this.state == "exited") { + return { error: "wrongState" }; + } + + update(this._options, aRequest.options || {}); + // Clear existing sources, so they can be recreated on next access. + this._sources = null; + + return {}; + }, + + /** + * Pause the debuggee, by entering a nested event loop, and return a 'paused' + * packet to the client. + * + * @param Debugger.Frame aFrame + * The newest debuggee frame in the stack. + * @param object aReason + * An object with a 'type' property containing the reason for the pause. + * @param function onPacket + * Hook to modify the packet before it is sent. Feel free to return a + * promise. + */ + _pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason, + onPacket=function (k) k) { + try { + let packet = this._paused(aFrame); + if (!packet) { + return undefined; + } + packet.why = aReason; + resolve(onPacket(packet)).then(this.conn.send.bind(this.conn)); + _lockVM(aFrame, aFrame.script); + return this._nest(); + } catch(e) { + let msg = "Got an exception during TA__pauseAndRespond: " + e + + ": " + e.stack; + // Cu.reportError(msg); + dumpn(msg); + return undefined; + } + }, + + /** + * Handle a protocol request to resume execution of the debuggee. + */ + onResume: function TA_onResume(aRequest) { + if (this._state !== "paused") { + return { + error: "wrongState", + message: "Can't resume when debuggee isn't paused. Current state is '" + + this._state + "'" + }; + } + + // In case of multiple nested event loops (due to multiple debuggers open in + // different tabs or multiple debugger clients connected to the same tab) + // only allow resumption in a LIFO order. + // if (DebuggerServer.xpcInspector.eventLoopNestLevel > 1) { + // let lastNestRequestor = DebuggerServer.xpcInspector.lastNestRequestor; + // if (lastNestRequestor.connection != this.conn) { + // return { error: "wrongOrder", + // message: "trying to resume in the wrong order.", + // lastPausedUrl: lastNestRequestor.url }; + // } + // } + + if (aRequest && aRequest.forceCompletion) { + // TODO: remove this when Debugger.Frame.prototype.pop is implemented in + // bug 736733. + if (typeof this.frame.pop != "function") { + return { error: "notImplemented", + message: "forced completion is not yet implemented." }; + } + + this.dbg.getNewestFrame().pop(aRequest.completionValue); + let packet = this._resumed(); + // DebuggerServer.xpcInspector.exitNestedEventLoop(); + _unlockVM(); + return { type: "resumeLimit", frameFinished: aRequest.forceCompletion }; + } + + if (aRequest && aRequest.resumeLimit) { + // Bind these methods because some of the hooks are called with 'this' + // set to the current frame. + let pauseAndRespond = (aFrame, onPacket=function (k) k) => { + this._pauseAndRespond(aFrame, { type: "resumeLimit" }, onPacket); + }; + let createValueGrip = this.createValueGrip.bind(this); + + let startFrame = this.youngestFrame; + let startLine; + if (this.youngestFrame.script) { + let offset = this.youngestFrame.offset; + startLine = this.youngestFrame.script.getOffsetLine(offset); + } + + // Define the JS hook functions for stepping. + + let onEnterFrame = aFrame => { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + return pauseAndRespond(aFrame); + }; + + let thread = this; + + let onPop = function TA_onPop(aCompletion) { + // onPop is called with 'this' set to the current frame. + if (thread.sources.isBlackBoxed(this.script.url)) { + return undefined; + } + + // Note that we're popping this frame; we need to watch for + // subsequent step events on its caller. + this.reportedPop = true; + + return pauseAndRespond(this, (aPacket) => { + aPacket.why.frameFinished = {}; + if (!aCompletion) { + aPacket.why.frameFinished.terminated = true; + } else if (aCompletion.hasOwnProperty("return")) { + aPacket.why.frameFinished.return = createValueGrip(aCompletion.return); + } else if (aCompletion.hasOwnProperty("yield")) { + aPacket.why.frameFinished.return = createValueGrip(aCompletion.yield); + } else { + aPacket.why.frameFinished.throw = createValueGrip(aCompletion.throw); + } + return aPacket; + }); + }; + + let onStep = function TA_onStep() { + // onStep is called with 'this' set to the current frame. + + if (thread.sources.isBlackBoxed(this.script.url)) { + return undefined; + } + + // If we've changed frame or line, then report that. + if (this !== startFrame || + (this.script && + this.script.getOffsetLine(this.offset) != startLine)) { + return pauseAndRespond(this); + } + + // Otherwise, let execution continue. + return undefined; + }; + + let steppingType = aRequest.resumeLimit.type; + if (["step", "next", "finish"].indexOf(steppingType) == -1) { + return { error: "badParameterType", + message: "Unknown resumeLimit type" }; + } + // Make sure there is still a frame on the stack if we are to continue + // stepping. + let stepFrame = this._getNextStepFrame(startFrame); + if (stepFrame) { + switch (steppingType) { + case "step": + this.dbg.onEnterFrame = onEnterFrame; + // Fall through. + case "next": + stepFrame.onStep = onStep; + stepFrame.onPop = onPop; + break; + case "finish": + stepFrame.onPop = onPop; + } + } + + } + + if (aRequest && aRequest.pauseOnExceptions) { + this.dbg.onExceptionUnwind = this.onExceptionUnwind.bind(this); + } + let packet = this._resumed(); + _unlockVM(); + // DebuggerServer.xpcInspector.exitNestedEventLoop(); + return packet; + }, + + /** + * Helper method that returns the next frame when stepping. + */ + _getNextStepFrame: function TA__getNextStepFrame(aFrame) { + let stepFrame = aFrame.reportedPop ? aFrame.older : aFrame; + if (!stepFrame || !stepFrame.script) { + stepFrame = null; + } + return stepFrame; + }, + + onClientEvaluate: function TA_onClientEvaluate(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Debuggee must be paused to evaluate code." }; + }; + + let frame = this._requestFrame(aRequest.frame); + if (!frame) { + return { error: "unknownFrame", + message: "Evaluation frame not found" }; + } + + if (!frame.environment) { + return { error: "notDebuggee", + message: "cannot access the environment of this frame." }; + }; + + // We'll clobber the youngest frame if the eval causes a pause, so + // save our frame now to be restored after eval returns. + // XXX: or we could just start using dbg.getNewestFrame() now that it + // works as expected. + let youngest = this.youngestFrame; + + // Put ourselves back in the running state and inform the client. + let resumedPacket = this._resumed(); + this.conn.send(resumedPacket); + + // Run the expression. + // XXX: test syntax errors + let completion = frame.eval(aRequest.expression); + + // Put ourselves back in the pause state. + let packet = this._paused(youngest); + packet.why = { type: "clientEvaluated", + frameFinished: this.createProtocolCompletionValue(completion) }; + + // Return back to our previous pause's event loop. + return packet; + }, + + onFrames: function TA_onFrames(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Stack frames are only available while the debuggee is paused."}; + } + + let start = aRequest.start ? aRequest.start : 0; + let count = aRequest.count; + + // Find the starting frame... + let frame = this.youngestFrame; + let i = 0; + while (frame && (i < start)) { + frame = frame.older; + i++; + } + + // Return request.count frames, or all remaining + // frames if count is not defined. + let frames = []; + let promises = []; + for (; frame && (!count || i < (start + count)); i++, frame=frame.older) { + let form = this._createFrameActor(frame).form(); + form.depth = i; + frames.push(form); + + let promise = this.sources.getOriginalLocation(form.where.url, + form.where.line) + .then(function (aOrigLocation) { + form.where = aOrigLocation; + }); + promises.push(promise); + } + + return all(promises).then(function () { + return { frames: frames }; + }); + }, + + onReleaseMany: function TA_onReleaseMany(aRequest) { + if (!aRequest.actors) { + return { error: "missingParameter", + message: "no actors were specified" }; + } + + let res; + for each (let actorID in aRequest.actors) { + let actor = this.threadLifetimePool.get(actorID); + if (!actor) { + if (!res) { + res = { error: "notReleasable", + message: "Only thread-lifetime actors can be released." }; + } + continue; + } + actor.onRelease(); + } + return res ? res : {}; + }, + + /** + * Handle a protocol request to set a breakpoint. + */ + onSetBreakpoint: function TA_onSetBreakpoint(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Breakpoints can only be set while the debuggee is paused."}; + } + + // XXX: `originalColumn` is never used. See bug 827639. + let { url: originalSource, + line: originalLine, + column: originalColumn } = aRequest.location; + + let locationPromise = this.sources.getGeneratedLocation(originalSource, + originalLine) + return locationPromise.then((aLocation) => { + let line = aLocation.line; + if (this.dbg.findScripts({ url: aLocation.url }).length == 0 || + line < 0 || + line == null) { + return { error: "noScript" }; + } + + // Add the breakpoint to the store for later reuse, in case it belongs to a + // script that hasn't appeared yet. + if (!this._breakpointStore[aLocation.url]) { + this._breakpointStore[aLocation.url] = []; + } + let scriptBreakpoints = this._breakpointStore[aLocation.url]; + scriptBreakpoints[line] = { + url: aLocation.url, + line: line, + column: aLocation.column + }; + + let response = this._setBreakpoint(aLocation); + // If the original location of our generated location is different from + // the original location we attempted to set the breakpoint on, we will + // need to know so that we can set actualLocation on the response. + let originalLocation = this.sources.getOriginalLocation(aLocation.url, + aLocation.line); + + return all([response, originalLocation]) + .then(([aResponse, {url, line}]) => { + if (aResponse.actualLocation) { + let actualOrigLocation = this.sources.getOriginalLocation( + aResponse.actualLocation.url, aResponse.actualLocation.line); + return actualOrigLocation.then(function ({ url, line }) { + if (url !== originalSource || line !== originalLine) { + aResponse.actualLocation = { url: url, line: line }; + } + return aResponse; + }); + } + + if (url !== originalSource || line !== originalLine) { + aResponse.actualLocation = { url: url, line: line }; + } + + return aResponse; + }); + }); + }, + + /** + * Set a breakpoint using the jsdbg2 API. If the line on which the breakpoint + * is being set contains no code, then the breakpoint will slide down to the + * next line that has runnable code. In this case the server breakpoint cache + * will be updated, so callers that iterate over the breakpoint cache should + * take that into account. + * + * @param object aLocation + * The location of the breakpoint as specified in the protocol. + */ + _setBreakpoint: function TA__setBreakpoint(aLocation) { + let breakpoints = this._breakpointStore[aLocation.url]; + + // Get or create the breakpoint actor for the given location + let actor; + if (breakpoints[aLocation.line].actor) { + actor = breakpoints[aLocation.line].actor; + } else { + actor = breakpoints[aLocation.line].actor = new BreakpointActor(this, { + url: aLocation.url, + line: aLocation.line + }); + this._hooks.addToParentPool(actor); + } + + // Find all scripts matching the given location + let scripts = this.dbg.findScripts(aLocation); + if (scripts.length == 0) { + return { + error: "noScript", + actor: actor.actorID + }; + } + + /** + * For each script, if the given line has at least one entry point, set + * breakpoint on the bytecode offet for each of them. + */ + let found = false; + for (let script of scripts) { + let offsets = script.getLineOffsets(aLocation.line); + if (offsets.length > 0) { + for (let offset of offsets) { + script.setBreakpoint(offset, actor); + } + actor.addScript(script, this); + found = true; + } + } + if (found) { + return { + actor: actor.actorID + }; + } + + /** + * If we get here, no breakpoint was set. This is because the given line + * has no entry points, for example because it is empty. As a fallback + * strategy, we try to set the breakpoint on the smallest line greater + * than or equal to the given line that as at least one entry point. + */ + + // Find all innermost scripts matching the given location + let scripts = this.dbg.findScripts({ + url: aLocation.url, + line: aLocation.line, + innermost: true + }); + + /** + * For each innermost script, look for the smallest line greater than or + * equal to the given line that has one or more entry points. If found, set + * a breakpoint on the bytecode offset for each of its entry points. + */ + let actualLocation; + let found = false; + for (let script of scripts) { + let offsets = script.getAllOffsets(); + for (let line = aLocation.line; line < offsets.length; ++line) { + if (offsets[line]) { + for (let offset of offsets[line]) { + script.setBreakpoint(offset, actor); + } + actor.addScript(script, this); + if (!actualLocation) { + actualLocation = { + url: aLocation.url, + line: line, + column: 0 + }; + } + found = true; + break; + } + } + } + if (found) { + if (breakpoints[actualLocation.line] && + breakpoints[actualLocation.line].actor) { + /** + * We already have a breakpoint actor for the actual location, so + * actor we created earlier is now redundant. Delete it, update the + * breakpoint store, and return the actor for the actual location. + */ + actor.onDelete(); + delete breakpoints[aLocation.line]; + return { + actor: breakpoints[actualLocation.line].actor.actorID, + actualLocation: actualLocation + }; + } else { + /** + * We don't have a breakpoint actor for the actual location yet. + * Instead or creating a new actor, reuse the actor we created earlier, + * and update the breakpoint store. + */ + actor.location = actualLocation; + breakpoints[actualLocation.line] = breakpoints[aLocation.line]; + delete breakpoints[aLocation.line]; + // WARNING: This overwrites aLocation.line + breakpoints[actualLocation.line].line = actualLocation.line; + return { + actor: actor.actorID, + actualLocation: actualLocation + }; + } + } + + /** + * If we get here, no line matching the given line was found, so just + * epically. + */ + return { + error: "noCodeAtLineColumn", + actor: actor.actorID + }; + }, + + /** + * Get the script and source lists from the debugger. + * + * TODO bug 637572: we should be dealing with sources directly, not inferring + * them through scripts. + */ + _discoverSources: function TA__discoverSources() { + // Only get one script per url. + let scriptsByUrl = {}; + for (let s of this.dbg.findScripts()) { + scriptsByUrl[s.url] = s; + } + + return all([this.sources.sourcesForScript(scriptsByUrl[s]) + for (s of Object.keys(scriptsByUrl))]); + }, + + onSources: function TA_onSources(aRequest) { + return this._discoverSources().then(() => { + return { + sources: [s.form() for (s of this.sources.iter())] + }; + }); + }, + + /** + * Disassociate all breakpoint actors from their scripts and clear the + * breakpoint handlers. This method can be used when the thread actor intends + * to keep the breakpoint store, but needs to clear any actual breakpoints, + * e.g. due to a page navigation. This way the breakpoint actors' script + * caches won't hold on to the Debugger.Script objects leaking memory. + */ + disableAllBreakpoints: function () { + for (let url in this._breakpointStore) { + for (let line in this._breakpointStore[url]) { + let bp = this._breakpointStore[url][line]; + bp.actor.removeScripts(); + } + } + }, + + /** + * Handle a protocol request to pause the debuggee. + */ + onInterrupt: function TA_onInterrupt(aRequest) { + if (this.state == "exited") { + return { type: "exited" }; + } else if (this.state == "paused") { + // TODO: return the actual reason for the existing pause. + return { type: "paused", why: { type: "alreadyPaused" } }; + } else if (this.state != "running") { + return { error: "wrongState", + message: "Received interrupt request in " + this.state + + " state." }; + } + + try { + // Put ourselves in the paused state. + let packet = this._paused(); + if (!packet) { + return { error: "notInterrupted" }; + } + packet.why = { type: "interrupted" }; + + // Send the response to the interrupt request now (rather than + // returning it), because we're going to start a nested event loop + // here. + this.conn.send(packet); + + // Start a nested event loop. + this._nest(); + + // We already sent a response to this request, don't send one + // now. + return null; + } catch (e) { + reportError(e); + return { error: "notInterrupted", message: e.toString() }; + } + }, + + /** + * Return the Debug.Frame for a frame mentioned by the protocol. + */ + _requestFrame: function TA_requestFrame(aFrameID) { + if (!aFrameID) { + return this.youngestFrame; + } + + if (this._framePool.has(aFrameID)) { + return this._framePool.get(aFrameID).frame; + } + + return undefined; + }, + + _paused: function TA_paused(aFrame) { + // We don't handle nested pauses correctly. Don't try - if we're + // paused, just continue running whatever code triggered the pause. + // We don't want to actually have nested pauses (although we + // have nested event loops). If code runs in the debuggee during + // a pause, it should cause the actor to resume (dropping + // pause-lifetime actors etc) and then repause when complete. + + if (this.state === "paused") { + return undefined; + } + + // Clear stepping hooks. + this.dbg.onEnterFrame = undefined; + this.dbg.onExceptionUnwind = undefined; + if (aFrame) { + aFrame.onStep = undefined; + aFrame.onPop = undefined; + } + + this._state = "paused"; + + // Save the pause frame (if any) as the youngest frame for + // stack viewing. + this.youngestFrame = aFrame; + + // Create the actor pool that will hold the pause actor and its + // children. + dbg_assert(!this._pausePool); + this._pausePool = new ActorPool(this.conn); + this.conn.addActorPool(this._pausePool); + + // Give children of the pause pool a quick link back to the + // thread... + this._pausePool.threadActor = this; + + // Create the pause actor itself... + dbg_assert(!this._pauseActor); + this._pauseActor = new PauseActor(this._pausePool); + this._pausePool.addActor(this._pauseActor); + + // Update the list of frames. + let poppedFrames = this._updateFrames(); + + // Send off the paused packet and spin an event loop. + let packet = { from: this.actorID, + type: "paused", + actor: this._pauseActor.actorID }; + if (aFrame) { + packet.frame = this._createFrameActor(aFrame).form(); + } + + if (poppedFrames) { + packet.poppedFrames = poppedFrames; + } + + return packet; + }, + + _nest: function TA_nest() { + if (this._hooks.preNest) { + var nestData = this._hooks.preNest(); + } + + let requestor = Object.create(null); + requestor.url = this._hooks.url; + requestor.connection = this.conn; + // DebuggerServer.xpcInspector.enterNestedEventLoop(requestor); + + dbg_assert(this.state === "running"); + + if (this._hooks.postNest) { + this._hooks.postNest(nestData) + } + + // "continue" resumption value. + return undefined; + }, + + _resumed: function TA_resumed() { + this._state = "running"; + + // Drop the actors in the pause actor pool. + this.conn.removeActorPool(this._pausePool); + + this._pausePool = null; + this._pauseActor = null; + this.youngestFrame = null; + + return { from: this.actorID, type: "resumed" }; + }, + + /** + * Expire frame actors for frames that have been popped. + * + * @returns A list of actor IDs whose frames have been popped. + */ + _updateFrames: function TA_updateFrames() { + let popped = []; + + // Create the actor pool that will hold the still-living frames. + let framePool = new ActorPool(this.conn); + let frameList = []; + + for each (let frameActor in this._frameActors) { + if (frameActor.frame.live) { + framePool.addActor(frameActor); + frameList.push(frameActor); + } else { + popped.push(frameActor.actorID); + } + } + + // Remove the old frame actor pool, this will expire + // any actors that weren't added to the new pool. + if (this._framePool) { + this.conn.removeActorPool(this._framePool); + } + + this._frameActors = frameList; + this._framePool = framePool; + this.conn.addActorPool(framePool); + + return popped; + }, + + _createFrameActor: function TA_createFrameActor(aFrame) { + if (aFrame.actor) { + return aFrame.actor; + } + + let actor = new FrameActor(aFrame, this); + this._frameActors.push(actor); + this._framePool.addActor(actor); + aFrame.actor = actor; + + return actor; + }, + + /** + * Create and return an environment actor that corresponds to the provided + * Debugger.Environment. + * @param Debugger.Environment aEnvironment + * The lexical environment we want to extract. + * @param object aPool + * The pool where the newly-created actor will be placed. + * @return The EnvironmentActor for aEnvironment or undefined for host + * functions or functions scoped to a non-debuggee global. + */ + createEnvironmentActor: + function TA_createEnvironmentActor(aEnvironment, aPool) { + if (!aEnvironment) { + return undefined; + } + + if (aEnvironment.actor) { + return aEnvironment.actor; + } + + let actor = new EnvironmentActor(aEnvironment, this); + this._environmentActors.push(actor); + aPool.addActor(actor); + aEnvironment.actor = actor; + + return actor; + }, + + /** + * Create a grip for the given debuggee value. If the value is an + * object, will create an actor with the given lifetime. + */ + createValueGrip: function TA_createValueGrip(aValue, aPool=false) { + if (!aPool) { + aPool = this._pausePool; + } + let type = typeof(aValue); + + if (type === "string" && this._stringIsLong(aValue)) { + return this.longStringGrip(aValue, aPool); + } + + if (type === "boolean" || type === "string" || type === "number") { + return aValue; + } + + if (aValue === null) { + return { type: "null" }; + } + + if (aValue === undefined) { + return { type: "undefined" } + } + + if (typeof(aValue) === "object") { + return this.objectGrip(aValue, aPool); + } + + dbg_assert(false, "Failed to provide a grip for: " + aValue); + return null; + }, + + /** + * Return a protocol completion value representing the given + * Debugger-provided completion value. + */ + createProtocolCompletionValue: + function TA_createProtocolCompletionValue(aCompletion) { + let protoValue = {}; + if ("return" in aCompletion) { + protoValue.return = this.createValueGrip(aCompletion.return); + } else if ("yield" in aCompletion) { + protoValue.return = this.createValueGrip(aCompletion.yield); + } else if ("throw" in aCompletion) { + protoValue.throw = this.createValueGrip(aCompletion.throw); + } else { + protoValue.terminated = true; + } + return protoValue; + }, + + /** + * Create a grip for the given debuggee object. + * + * @param aValue Debugger.Object + * The debuggee object value. + * @param aPool ActorPool + * The actor pool where the new object actor will be added. + */ + objectGrip: function TA_objectGrip(aValue, aPool) { + if (!aPool.objectActors) { + aPool.objectActors = new WeakMap(); + } + + if (aPool.objectActors.has(aValue)) { + return aPool.objectActors.get(aValue).grip(); + } else if (this.threadLifetimePool.objectActors.has(aValue)) { + return this.threadLifetimePool.objectActors.get(aValue).grip(); + } + + let actor = new PauseScopedObjectActor(aValue, this); + aPool.addActor(actor); + aPool.objectActors.set(aValue, actor); + return actor.grip(); + }, + + /** + * Create a grip for the given debuggee object with a pause lifetime. + * + * @param aValue Debugger.Object + * The debuggee object value. + */ + pauseObjectGrip: function TA_pauseObjectGrip(aValue) { + if (!this._pausePool) { + throw "Object grip requested while not paused."; + } + + return this.objectGrip(aValue, this._pausePool); + }, + + /** + * Extend the lifetime of the provided object actor to thread lifetime. + * + * @param aActor object + * The object actor. + */ + threadObjectGrip: function TA_threadObjectGrip(aActor) { + // We want to reuse the existing actor ID, so we just remove it from the + // current pool's weak map and then let pool.addActor do the rest. + aActor.registeredPool.objectActors.delete(aActor.obj); + this.threadLifetimePool.addActor(aActor); + this.threadLifetimePool.objectActors.set(aActor.obj, aActor); + }, + + /** + * Handle a protocol request to promote multiple pause-lifetime grips to + * thread-lifetime grips. + * + * @param aRequest object + * The protocol request object. + */ + onThreadGrips: function OA_onThreadGrips(aRequest) { + if (this.state != "paused") { + return { error: "wrongState" }; + } + + if (!aRequest.actors) { + return { error: "missingParameter", + message: "no actors were specified" }; + } + + for (let actorID of aRequest.actors) { + let actor = this._pausePool.get(actorID); + if (actor) { + this.threadObjectGrip(actor); + } + } + return {}; + }, + + /** + * Create a grip for the given string. + * + * @param aString String + * The string we are creating a grip for. + * @param aPool ActorPool + * The actor pool where the new actor will be added. + */ + longStringGrip: function TA_longStringGrip(aString, aPool) { + if (!aPool.longStringActors) { + aPool.longStringActors = {}; + } + + if (aPool.longStringActors.hasOwnProperty(aString)) { + return aPool.longStringActors[aString].grip(); + } + + let actor = new LongStringActor(aString, this); + aPool.addActor(actor); + aPool.longStringActors[aString] = actor; + return actor.grip(); + }, + + /** + * Create a long string grip that is scoped to a pause. + * + * @param aString String + * The string we are creating a grip for. + */ + pauseLongStringGrip: function TA_pauseLongStringGrip (aString) { + return this.longStringGrip(aString, this._pausePool); + }, + + /** + * Create a long string grip that is scoped to a thread. + * + * @param aString String + * The string we are creating a grip for. + */ + threadLongStringGrip: function TA_pauseLongStringGrip (aString) { + return this.longStringGrip(aString, this._threadLifetimePool); + }, + + /** + * Returns true if the string is long enough to use a LongStringActor instead + * of passing the value directly over the protocol. + * + * @param aString String + * The string we are checking the length of. + */ + _stringIsLong: function TA__stringIsLong(aString) { + return aString.length >= DebuggerServer.LONG_STRING_LENGTH; + }, + + // JS Debugger API hooks. + + /** + * A function that the engine calls when a call to a debug event hook, + * breakpoint handler, watchpoint handler, or similar function throws some + * exception. + * + * @param aException exception + * The exception that was thrown in the debugger code. + */ + uncaughtExceptionHook: function TA_uncaughtExceptionHook(aException) { + dumpn("Got an exception: " + aException.message + "\n" + aException.stack); + }, + + /** + * A function that the engine calls when a debugger statement has been + * executed in the specified frame. + * + * @param aFrame Debugger.Frame + * The stack frame that contained the debugger statement. + */ + onDebuggerStatement: function TA_onDebuggerStatement(aFrame) { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + return this._pauseAndRespond(aFrame, { type: "debuggerStatement" }); + }, + + /** + * A function that the engine calls when an exception has been thrown and has + * propagated to the specified frame. + * + * @param aFrame Debugger.Frame + * The youngest remaining stack frame. + * @param aValue object + * The exception that was thrown. + */ + onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + try { + let packet = this._paused(aFrame); + if (!packet) { + return undefined; + } + + packet.why = { type: "exception", + exception: this.createValueGrip(aValue) }; + this.conn.send(packet); + return this._nest(); + } catch(e) { + log("Got an exception during TA_onExceptionUnwind: " + e + + ": " + e.stack); + return undefined; + } + }, + + /** + * A function that the engine calls when a new script has been loaded into the + * scope of the specified debuggee global. + * + * @param aScript Debugger.Script + * The source script that has been loaded into a debuggee compartment. + * @param aGlobal Debugger.Object + * A Debugger.Object instance whose referent is the global object. + */ + onNewScript: function TA_onNewScript(aScript, aGlobal) { + this._addScript(aScript); + this.sources.sourcesForScript(aScript); + }, + + onNewSource: function TA_onNewSource(aSource) { + this.conn.send({ + from: this.actorID, + type: "newSource", + source: aSource.form() + }); + }, + + /** + * Check if scripts from the provided source URL are allowed to be stored in + * the cache. + * + * @param aSourceUrl String + * The url of the script's source that will be stored. + * @returns true, if the script can be added, false otherwise. + */ + _allowSource: function TA__allowSource(aSourceUrl) { + // Ignore anything we don't have a URL for (eval scripts, for example). + if (!aSourceUrl) + return false; + // Ignore XBL bindings for content debugging. + if (aSourceUrl.indexOf("chrome://") == 0) { + return false; + } + // Ignore about:* pages for content debugging. + if (aSourceUrl.indexOf("about:") == 0) { + return false; + } + return true; + }, + + /** + * Restore any pre-existing breakpoints to the scripts that we have access to. + */ + _restoreBreakpoints: function TA__restoreBreakpoints() { + for (let s of this.dbg.findScripts()) { + this._addScript(s); + } + }, + + /** + * Add the provided script to the server cache. + * + * @param aScript Debugger.Script + * The source script that will be stored. + * @returns true, if the script was added; false otherwise. + */ + _addScript: function TA__addScript(aScript) { + if (!this._allowSource(aScript.url)) { + return false; + } + + // Set any stored breakpoints. + let existing = this._breakpointStore[aScript.url]; + if (existing) { + let endLine = aScript.startLine + aScript.lineCount - 1; + // Iterate over the lines backwards, so that sliding breakpoints don't + // affect the loop. + for (let line = existing.length - 1; line >= aScript.startLine; line--) { + let bp = existing[line]; + // Only consider breakpoints that are not already associated with + // scripts, and limit search to the line numbers contained in the new + // script. + if (bp && !bp.actor.scripts.length && line <= endLine) { + this._setBreakpoint(bp); + } + } + } + return true; + }, + +}; + +ThreadActor.prototype.requestTypes = { + "attach": ThreadActor.prototype.onAttach, + "detach": ThreadActor.prototype.onDetach, + "reconfigure": ThreadActor.prototype.onReconfigure, + "resume": ThreadActor.prototype.onResume, + "clientEvaluate": ThreadActor.prototype.onClientEvaluate, + "frames": ThreadActor.prototype.onFrames, + "interrupt": ThreadActor.prototype.onInterrupt, + "releaseMany": ThreadActor.prototype.onReleaseMany, + "setBreakpoint": ThreadActor.prototype.onSetBreakpoint, + "sources": ThreadActor.prototype.onSources, + "threadGrips": ThreadActor.prototype.onThreadGrips +}; + + +/** + * Creates a PauseActor. + * + * PauseActors exist for the lifetime of a given debuggee pause. Used to + * scope pause-lifetime grips. + * + * @param ActorPool aPool + * The actor pool created for this pause. + */ +function PauseActor(aPool) +{ + this.pool = aPool; +} + +PauseActor.prototype = { + actorPrefix: "pause" +}; + + +/** + * A base actor for any actors that should only respond receive messages in the + * paused state. Subclasses may expose a `threadActor` which is used to help + * determine when we are in a paused state. Subclasses should set their own + * "constructor" property if they want better error messages. You should never + * instantiate a PauseScopedActor directly, only through subclasses. + */ +function PauseScopedActor() +{ +} + +/** + * A function decorator for creating methods to handle protocol messages that + * should only be received while in the paused state. + * + * @param aMethod Function + * The function we are decorating. + */ +PauseScopedActor.withPaused = function PSA_withPaused(aMethod) { + return function () { + if (this.isPaused()) { + return aMethod.apply(this, arguments); + } else { + return this._wrongState(); + } + }; +}; + +PauseScopedActor.prototype = { + + /** + * Returns true if we are in the paused state. + */ + isPaused: function PSA_isPaused() { + // When there is not a ThreadActor available (like in the webconsole) we + // have to be optimistic and assume that we are paused so that we can + // respond to requests. + return this.threadActor ? this.threadActor.state === "paused" : true; + }, + + /** + * Returns the wrongState response packet for this actor. + */ + _wrongState: function PSA_wrongState() { + return { + error: "wrongState", + message: this.constructor.name + + " actors can only be accessed while the thread is paused." + }; + } +}; + + +/** + * A SourceActor provides information about the source of a script. + * + * @param aUrl String + * The url of the source we are representing. + * @param aThreadActor ThreadActor + * The current thread actor. + * @param aSourceMap SourceMapConsumer + * Optional. The source map that introduced this source, if available. + */ +function SourceActor(aUrl, aThreadActor, aSourceMap=null) { + this._threadActor = aThreadActor; + this._url = aUrl; + this._sourceMap = aSourceMap; +} + +SourceActor.prototype = { + constructor: SourceActor, + actorPrefix: "source", + + get threadActor() this._threadActor, + get url() this._url, + + form: function SA_form() { + return { + actor: this.actorID, + url: this._url, + isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url) + // TODO bug 637572: introductionScript + }; + }, + + disconnect: function LSA_disconnect() { + if (this.registeredPool && this.registeredPool.sourceActors) { + delete this.registeredPool.sourceActors[this.actorID]; + } + }, + + /** + * Handler for the "source" packet. + */ + onSource: function SA_onSource(aRequest) { + let sourceContent = null; + if (this._sourceMap) { + sourceContent = this._sourceMap.sourceContentFor(this._url); + } + + if (sourceContent) { + return { + from: this.actorID, + source: this.threadActor.createValueGrip( + sourceContent, this.threadActor.threadLifetimePool) + }; + } + + // XXX bug 865252: Don't load from the cache if this is a source mapped + // source because we can't guarantee that the cache has the most up to date + // content for this source like we can if it isn't source mapped. + return fetch(this._url, { loadFromCache: !this._sourceMap }) + .then((aSource) => { + return this.threadActor.createValueGrip( + aSource, this.threadActor.threadLifetimePool); + }) + .then((aSourceGrip) => { + return { + from: this.actorID, + source: aSourceGrip + }; + }, (aError) => { + let msg = "Got an exception during SA_onSource: " + aError + + "\n" + aError.stack; + // Cu.reportError(msg); + dumpn(msg); + return { + "from": this.actorID, + "error": "loadSourceError", + "message": "Could not load the source for " + this._url + "." + }; + }); + }, + + /** + * Handler for the "blackbox" packet. + */ + onBlackBox: function SA_onBlackBox(aRequest) { + this.threadActor.sources.blackBox(this.url); + let packet = { + from: this.actorID + }; + if (this.threadActor.state == "paused" + && this.threadActor.youngestFrame + && this.threadActor.youngestFrame.script.url == this.url) { + packet.pausedInSource = true; + } + return packet; + }, + + /** + * Handler for the "unblackbox" packet. + */ + onUnblackBox: function SA_onUnblackBox(aRequest) { + this.threadActor.sources.unblackBox(this.url); + return { + from: this.actorID + }; + } +}; + +SourceActor.prototype.requestTypes = { + "source": SourceActor.prototype.onSource, + "blackbox": SourceActor.prototype.onBlackBox, + "unblackbox": SourceActor.prototype.onUnblackBox +}; + + +/** + * Creates an actor for the specified object. + * + * @param aObj Debugger.Object + * The debuggee object. + * @param aThreadActor ThreadActor + * The parent thread actor for this object. + */ +function ObjectActor(aObj, aThreadActor) +{ + this.obj = aObj; + this.threadActor = aThreadActor; +} + +ObjectActor.prototype = { + actorPrefix: "obj", + + /** + * Returns a grip for this actor for returning in a protocol message. + */ + grip: function OA_grip() { + let g = { + "type": "object", + "class": this.obj.class, + "actor": this.actorID, + "extensible": this.obj.isExtensible(), + "frozen": this.obj.isFrozen(), + "sealed": this.obj.isSealed() + }; + + // Add additional properties for functions. + if (this.obj.class === "Function") { + if (this.obj.name) { + g.name = this.obj.name; + } else if (this.obj.displayName) { + g.displayName = this.obj.displayName; + } + + // Check if the developer has added a de-facto standard displayName + // property for us to use. + let desc = this.obj.getOwnPropertyDescriptor("displayName"); + if (desc && desc.value && typeof desc.value == "string") { + g.userDisplayName = this.threadActor.createValueGrip(desc.value); + } + } + + return g; + }, + + /** + * Releases this actor from the pool. + */ + release: function OA_release() { + if (this.registeredPool.objectActors) { + this.registeredPool.objectActors.delete(this.obj); + } + this.registeredPool.removeActor(this); + }, + + /** + * Handle a protocol request to provide the names of the properties defined on + * the object and not its prototype. + * + * @param aRequest object + * The protocol request object. + */ + onOwnPropertyNames: function OA_onOwnPropertyNames(aRequest) { + return { from: this.actorID, + ownPropertyNames: this.obj.getOwnPropertyNames() }; + }, + + /** + * Handle a protocol request to provide the prototype and own properties of + * the object. + * + * @param aRequest object + * The protocol request object. + */ + onPrototypeAndProperties: function OA_onPrototypeAndProperties(aRequest) { + let ownProperties = Object.create(null); + let names; + try { + names = this.obj.getOwnPropertyNames(); + } catch (ex) { + // The above can throw if this.obj points to a dead object. + // TODO: we should use Cu.isDeadWrapper() - see bug 885800. + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(null), + ownProperties: ownProperties, + safeGetterValues: Object.create(null) }; + } + for (let name of names) { + ownProperties[name] = this._propertyDescriptor(name); + } + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(this.obj.proto), + ownProperties: ownProperties, + safeGetterValues: this._findSafeGetterValues(ownProperties) }; + }, + + /** + * Find the safe getter values for the current Debugger.Object, |this.obj|. + * + * @private + * @param object aOwnProperties + * The object that holds the list of known ownProperties for + * |this.obj|. + * @return object + * An object that maps property names to safe getter descriptors as + * defined by the remote debugging protocol. + */ + _findSafeGetterValues: function OA__findSafeGetterValues(aOwnProperties) + { + let safeGetterValues = Object.create(null); + let obj = this.obj; + let level = 0; + + while (obj) { + let getters = this._findSafeGetters(obj); + for (let name of getters) { + // Avoid overwriting properties from prototypes closer to this.obj. Also + // avoid providing safeGetterValues from prototypes if property |name| + // is already defined as an own property. + if (name in safeGetterValues || + (obj != this.obj && name in aOwnProperties)) { + continue; + } + + let desc = null, getter = null; + try { + desc = obj.getOwnPropertyDescriptor(name); + getter = desc.get; + } catch (ex) { + // The above can throw if the cache becomes stale. + } + if (!getter) { + obj._safeGetters = null; + continue; + } + + let result = getter.call(this.obj); + if (result && !("throw" in result)) { + let getterValue = undefined; + if ("return" in result) { + getterValue = result.return; + } else if ("yield" in result) { + getterValue = result.yield; + } + // WebIDL attributes specified with the LenientThis extended attribute + // return undefined and should be ignored. + if (getterValue !== undefined) { + safeGetterValues[name] = { + getterValue: this.threadActor.createValueGrip(getterValue), + getterPrototypeLevel: level, + enumerable: desc.enumerable, + writable: level == 0 ? desc.writable : true, + }; + } + } + } + + obj = obj.proto; + level++; + } + + return safeGetterValues; + }, + + /** + * Find the safe getters for a given Debugger.Object. Safe getters are native + * getters which are safe to execute. + * + * @private + * @param Debugger.Object aObject + * The Debugger.Object where you want to find safe getters. + * @return Set + * A Set of names of safe getters. This result is cached for each + * Debugger.Object. + */ + _findSafeGetters: function OA__findSafeGetters(aObject) + { + if (aObject._safeGetters) { + return aObject._safeGetters; + } + + let getters = new Set(); + for (let name of aObject.getOwnPropertyNames()) { + let desc = null; + try { + desc = aObject.getOwnPropertyDescriptor(name); + } catch (e) { + // Calling getOwnPropertyDescriptor on wrapped native prototypes is not + // allowed (bug 560072). + } + if (!desc || desc.value !== undefined || !("get" in desc)) { + continue; + } + + let fn = desc.get; + if (fn && fn.callable && fn.class == "Function" && + fn.script === undefined) { + getters.add(name); + } + } + + aObject._safeGetters = getters; + return getters; + }, + + /** + * Handle a protocol request to provide the prototype of the object. + * + * @param aRequest object + * The protocol request object. + */ + onPrototype: function OA_onPrototype(aRequest) { + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(this.obj.proto) }; + }, + + /** + * Handle a protocol request to provide the property descriptor of the + * object's specified property. + * + * @param aRequest object + * The protocol request object. + */ + onProperty: function OA_onProperty(aRequest) { + if (!aRequest.name) { + return { error: "missingParameter", + message: "no property name was specified" }; + } + + return { from: this.actorID, + descriptor: this._propertyDescriptor(aRequest.name) }; + }, + + /** + * A helper method that creates a property descriptor for the provided object, + * properly formatted for sending in a protocol response. + * + * @param string aName + * The property that the descriptor is generated for. + */ + _propertyDescriptor: function OA_propertyDescriptor(aName) { + let desc; + try { + desc = this.obj.getOwnPropertyDescriptor(aName); + } catch (e) { + // Calling getOwnPropertyDescriptor on wrapped native prototypes is not + // allowed (bug 560072). Inform the user with a bogus, but hopefully + // explanatory, descriptor. + return { + configurable: false, + writable: false, + enumerable: false, + value: e.name + }; + } + + let retval = { + configurable: desc.configurable, + enumerable: desc.enumerable + }; + + if ("value" in desc) { + retval.writable = desc.writable; + retval.value = this.threadActor.createValueGrip(desc.value); + } else { + if ("get" in desc) { + retval.get = this.threadActor.createValueGrip(desc.get); + } + if ("set" in desc) { + retval.set = this.threadActor.createValueGrip(desc.set); + } + } + return retval; + }, + + /** + * Handle a protocol request to provide the source code of a function. + * + * @param aRequest object + * The protocol request object. + */ + onDecompile: function OA_onDecompile(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "decompile request is only valid for object grips " + + "with a 'Function' class." }; + } + + return { from: this.actorID, + decompiledCode: this.obj.decompile(!!aRequest.pretty) }; + }, + + /** + * Handle a protocol request to provide the parameters of a function. + * + * @param aRequest object + * The protocol request object. + */ + onParameterNames: function OA_onParameterNames(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "'parameterNames' request is only valid for object " + + "grips with a 'Function' class." }; + } + + return { parameterNames: this.obj.parameterNames }; + }, + + /** + * Handle a protocol request to release a thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onRelease: function OA_onRelease(aRequest) { + this.release(); + return {}; + }, +}; + +ObjectActor.prototype.requestTypes = { + "parameterNames": ObjectActor.prototype.onParameterNames, + "prototypeAndProperties": ObjectActor.prototype.onPrototypeAndProperties, + "prototype": ObjectActor.prototype.onPrototype, + "property": ObjectActor.prototype.onProperty, + "ownPropertyNames": ObjectActor.prototype.onOwnPropertyNames, + "decompile": ObjectActor.prototype.onDecompile, + "release": ObjectActor.prototype.onRelease, +}; + + +/** + * Creates a pause-scoped actor for the specified object. + * @see ObjectActor + */ +function PauseScopedObjectActor() +{ + ObjectActor.apply(this, arguments); +} + +PauseScopedObjectActor.prototype = Object.create(PauseScopedActor.prototype); + +update(PauseScopedObjectActor.prototype, ObjectActor.prototype); + +update(PauseScopedObjectActor.prototype, { + constructor: PauseScopedObjectActor, + + onOwnPropertyNames: + PauseScopedActor.withPaused(ObjectActor.prototype.onOwnPropertyNames), + + onPrototypeAndProperties: + PauseScopedActor.withPaused(ObjectActor.prototype.onPrototypeAndProperties), + + onPrototype: PauseScopedActor.withPaused(ObjectActor.prototype.onPrototype), + onProperty: PauseScopedActor.withPaused(ObjectActor.prototype.onProperty), + onDecompile: PauseScopedActor.withPaused(ObjectActor.prototype.onDecompile), + + onParameterNames: + PauseScopedActor.withPaused(ObjectActor.prototype.onParameterNames), + + /** + * Handle a protocol request to provide the lexical scope of a function. + * + * @param aRequest object + * The protocol request object. + */ + onScope: PauseScopedActor.withPaused(function OA_onScope(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "scope request is only valid for object grips with a" + + " 'Function' class." }; + } + + let envActor = this.threadActor.createEnvironmentActor(this.obj.environment, + this.registeredPool); + if (!envActor) { + return { error: "notDebuggee", + message: "cannot access the environment of this function." }; + } + + return { from: this.actorID, scope: envActor.form() }; + }), + + /** + * Handle a protocol request to promote a pause-lifetime grip to a + * thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onThreadGrip: PauseScopedActor.withPaused(function OA_onThreadGrip(aRequest) { + this.threadActor.threadObjectGrip(this); + return {}; + }), + + /** + * Handle a protocol request to release a thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onRelease: PauseScopedActor.withPaused(function OA_onRelease(aRequest) { + if (this.registeredPool !== this.threadActor.threadLifetimePool) { + return { error: "notReleasable", + message: "Only thread-lifetime actors can be released." }; + } + + this.release(); + return {}; + }), +}); + +update(PauseScopedObjectActor.prototype.requestTypes, { + "scope": PauseScopedObjectActor.prototype.onScope, + "threadGrip": PauseScopedObjectActor.prototype.onThreadGrip, +}); + + +/** + * Creates an actor for the specied "very long" string. "Very long" is specified + * at the server's discretion. + * + * @param aString String + * The string. + */ +function LongStringActor(aString) +{ + this.string = aString; + this.stringLength = aString.length; +} + +LongStringActor.prototype = { + + actorPrefix: "longString", + + disconnect: function LSA_disconnect() { + // Because longStringActors is not a weak map, we won't automatically leave + // it so we need to manually leave on disconnect so that we don't leak + // memory. + if (this.registeredPool && this.registeredPool.longStringActors) { + delete this.registeredPool.longStringActors[this.actorID]; + } + }, + + /** + * Returns a grip for this actor for returning in a protocol message. + */ + grip: function LSA_grip() { + return { + "type": "longString", + "initial": this.string.substring( + 0, DebuggerServer.LONG_STRING_INITIAL_LENGTH), + "length": this.stringLength, + "actor": this.actorID + }; + }, + + /** + * Handle a request to extract part of this actor's string. + * + * @param aRequest object + * The protocol request object. + */ + onSubstring: function LSA_onSubString(aRequest) { + return { + "from": this.actorID, + "substring": this.string.substring(aRequest.start, aRequest.end) + }; + }, + + /** + * Handle a request to release this LongStringActor instance. + */ + onRelease: function LSA_onRelease() { + // TODO: also check if registeredPool === threadActor.threadLifetimePool + // when the web console moves aray from manually releasing pause-scoped + // actors. + if (this.registeredPool.longStringActors) { + delete this.registeredPool.longStringActors[this.actorID]; + } + this.registeredPool.removeActor(this); + return {}; + }, +}; + +LongStringActor.prototype.requestTypes = { + "substring": LongStringActor.prototype.onSubstring, + "release": LongStringActor.prototype.onRelease +}; + + +/** + * Creates an actor for the specified stack frame. + * + * @param aFrame Debugger.Frame + * The debuggee frame. + * @param aThreadActor ThreadActor + * The parent thread actor for this frame. + */ +function FrameActor(aFrame, aThreadActor) +{ + this.frame = aFrame; + this.threadActor = aThreadActor; +} + +FrameActor.prototype = { + actorPrefix: "frame", + + /** + * A pool that contains frame-lifetime objects, like the environment. + */ + _frameLifetimePool: null, + get frameLifetimePool() { + if (!this._frameLifetimePool) { + this._frameLifetimePool = new ActorPool(this.conn); + this.conn.addActorPool(this._frameLifetimePool); + } + return this._frameLifetimePool; + }, + + /** + * Finalization handler that is called when the actor is being evicted from + * the pool. + */ + disconnect: function FA_disconnect() { + this.conn.removeActorPool(this._frameLifetimePool); + this._frameLifetimePool = null; + }, + + /** + * Returns a frame form for use in a protocol message. + */ + form: function FA_form() { + let form = { actor: this.actorID, + type: this.frame.type }; + if (this.frame.type === "call") { + form.callee = this.threadActor.createValueGrip(this.frame.callee); + } + + if (this.frame.environment) { + let envActor = this.threadActor + .createEnvironmentActor(this.frame.environment, + this.frameLifetimePool); + form.environment = envActor.form(); + } + form.this = this.threadActor.createValueGrip(this.frame.this); + form.arguments = this._args(); + if (this.frame.script) { + form.where = { url: this.frame.script.url, + line: this.frame.script.getOffsetLine(this.frame.offset) }; + form.isBlackBoxed = this.threadActor.sources.isBlackBoxed(this.frame.script.url) + } + + if (!this.frame.older) { + form.oldest = true; + } + + return form; + }, + + _args: function FA__args() { + if (!this.frame.arguments) { + return []; + } + + return [this.threadActor.createValueGrip(arg) + for each (arg in this.frame.arguments)]; + }, + + /** + * Handle a protocol request to pop this frame from the stack. + * + * @param aRequest object + * The protocol request object. + */ + onPop: function FA_onPop(aRequest) { + // TODO: remove this when Debugger.Frame.prototype.pop is implemented + if (typeof this.frame.pop != "function") { + return { error: "notImplemented", + message: "Popping frames is not yet implemented." }; + } + + while (this.frame != this.threadActor.dbg.getNewestFrame()) { + this.threadActor.dbg.getNewestFrame().pop(); + } + this.frame.pop(aRequest.completionValue); + + // TODO: return the watches property when frame pop watch actors are + // implemented. + return { from: this.actorID }; + } +}; + +FrameActor.prototype.requestTypes = { + "pop": FrameActor.prototype.onPop, +}; + + +/** + * Creates a BreakpointActor. BreakpointActors exist for the lifetime of their + * containing thread and are responsible for deleting breakpoints, handling + * breakpoint hits and associating breakpoints with scripts. + * + * @param ThreadActor aThreadActor + * The parent thread actor that contains this breakpoint. + * @param object aLocation + * The location of the breakpoint as specified in the protocol. + */ +function BreakpointActor(aThreadActor, aLocation) +{ + this.scripts = []; + this.threadActor = aThreadActor; + this.location = aLocation; +} + +BreakpointActor.prototype = { + actorPrefix: "breakpoint", + + /** + * Called when this same breakpoint is added to another Debugger.Script + * instance, in the case of a page reload. + * + * @param aScript Debugger.Script + * The new source script on which the breakpoint has been set. + * @param ThreadActor aThreadActor + * The parent thread actor that contains this breakpoint. + */ + addScript: function BA_addScript(aScript, aThreadActor) { + this.threadActor = aThreadActor; + this.scripts.push(aScript); + }, + + /** + * Remove the breakpoints from associated scripts and clear the script cache. + */ + removeScripts: function () { + for (let script of this.scripts) { + script.clearBreakpoint(this); + } + this.scripts = []; + }, + + /** + * A function that the engine calls when a breakpoint has been hit. + * + * @param aFrame Debugger.Frame + * The stack frame that contained the breakpoint. + */ + hit: function BA_hit(aFrame) { + if (this.threadActor.sources.isBlackBoxed(this.location.url)) { + return undefined; + } + + // TODO: add the rest of the breakpoints on that line (bug 676602). + let reason = { type: "breakpoint", actors: [ this.actorID ] }; + return this.threadActor._pauseAndRespond(aFrame, reason, (aPacket) => { + log("pause callback ..."); + + let { url, line } = aPacket.frame.where; + return this.threadActor.sources.getOriginalLocation(url, line) + .then(function (aOrigPosition) { + aPacket.frame.where = aOrigPosition; + return aPacket; + }); + }); + }, + + /** + * Handle a protocol request to remove this breakpoint. + * + * @param aRequest object + * The protocol request object. + */ + onDelete: function BA_onDelete(aRequest) { + // Remove from the breakpoint store. + let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url]; + delete scriptBreakpoints[this.location.line]; + this.threadActor._hooks.removeFromParentPool(this); + // Remove the actual breakpoint from the associated scripts. + this.removeScripts(); + + return { from: this.actorID }; + } +}; + +BreakpointActor.prototype.requestTypes = { + "delete": BreakpointActor.prototype.onDelete +}; + + +/** + * Creates an EnvironmentActor. EnvironmentActors are responsible for listing + * the bindings introduced by a lexical environment and assigning new values to + * those identifier bindings. + * + * @param Debugger.Environment aEnvironment + * The lexical environment that will be used to create the actor. + * @param ThreadActor aThreadActor + * The parent thread actor that contains this environment. + */ +function EnvironmentActor(aEnvironment, aThreadActor) +{ + this.obj = aEnvironment; + this.threadActor = aThreadActor; +} + +EnvironmentActor.prototype = { + actorPrefix: "environment", + + /** + * Return an environment form for use in a protocol message. + */ + form: function EA_form() { + let form = { actor: this.actorID }; + + // What is this environment's type? + if (this.obj.type == "declarative") { + form.type = this.obj.callee ? "function" : "block"; + } else { + form.type = this.obj.type; + } + + // Does this environment have a parent? + if (this.obj.parent) { + form.parent = (this.threadActor + .createEnvironmentActor(this.obj.parent, + this.registeredPool) + .form()); + } + + // Does this environment reflect the properties of an object as variables? + if (this.obj.type == "object" || this.obj.type == "with") { + form.object = this.threadActor.createValueGrip(this.obj.object); + } + + // Is this the environment created for a function call? + if (this.obj.callee) { + form.function = this.threadActor.createValueGrip(this.obj.callee); + } + + // Shall we list this environment's bindings? + if (this.obj.type == "declarative") { + form.bindings = this._bindings(); + } + + return form; + }, + + /** + * Return the identifier bindings object as required by the remote protocol + * specification. + */ + _bindings: function EA_bindings() { + let bindings = { arguments: [], variables: {} }; + + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands (bug 725815). + if (typeof this.obj.getVariable != "function") { + //if (typeof this.obj.getVariableDescriptor != "function") { + return bindings; + } + + let parameterNames; + if (this.obj.callee) { + parameterNames = this.obj.callee.parameterNames; + } + for each (let name in parameterNames) { + let arg = {}; + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands (bug 725815). + let desc = { + value: this.obj.getVariable(name), + configurable: false, + writable: true, + enumerable: true + }; + + // let desc = this.obj.getVariableDescriptor(name); + let descForm = { + enumerable: true, + configurable: desc.configurable + }; + if ("value" in desc) { + descForm.value = this.threadActor.createValueGrip(desc.value); + descForm.writable = desc.writable; + } else { + descForm.get = this.threadActor.createValueGrip(desc.get); + descForm.set = this.threadActor.createValueGrip(desc.set); + } + arg[name] = descForm; + bindings.arguments.push(arg); + } + + for each (let name in this.obj.names()) { + if (bindings.arguments.some(function exists(element) { + return !!element[name]; + })) { + continue; + } + + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands. + let desc = { + configurable: false, + writable: true, + enumerable: true + }; + try { + desc.value = this.obj.getVariable(name); + } catch (e) { + // Avoid "Debugger scope is not live" errors for |arguments|, introduced + // in bug 746601. + if (name != "arguments") { + throw e; + } + } + //let desc = this.obj.getVariableDescriptor(name); + let descForm = { + enumerable: true, + configurable: desc.configurable + }; + if ("value" in desc) { + descForm.value = this.threadActor.createValueGrip(desc.value); + descForm.writable = desc.writable; + } else { + descForm.get = this.threadActor.createValueGrip(desc.get); + descForm.set = this.threadActor.createValueGrip(desc.set); + } + bindings.variables[name] = descForm; + } + + return bindings; + }, + + /** + * Handle a protocol request to change the value of a variable bound in this + * lexical environment. + * + * @param aRequest object + * The protocol request object. + */ + onAssign: function EA_onAssign(aRequest) { + // TODO: enable the commented-out part when getVariableDescriptor lands + // (bug 725815). + /*let desc = this.obj.getVariableDescriptor(aRequest.name); + + if (!desc.writable) { + return { error: "immutableBinding", + message: "Changing the value of an immutable binding is not " + + "allowed" }; + }*/ + + try { + this.obj.setVariable(aRequest.name, aRequest.value); + } catch (e) { + if (e instanceof Debugger.DebuggeeWouldRun) { + return { error: "threadWouldRun", + cause: e.cause ? e.cause : "setter", + message: "Assigning a value would cause the debuggee to run" }; + } + // This should never happen, so let it complain loudly if it does. + throw e; + } + return { from: this.actorID }; + }, + + /** + * Handle a protocol request to fully enumerate the bindings introduced by the + * lexical environment. + * + * @param aRequest object + * The protocol request object. + */ + onBindings: function EA_onBindings(aRequest) { + return { from: this.actorID, + bindings: this._bindings() }; + } +}; + +EnvironmentActor.prototype.requestTypes = { + "assign": EnvironmentActor.prototype.onAssign, + "bindings": EnvironmentActor.prototype.onBindings +}; + +/** + * Override the toString method in order to get more meaningful script output + * for debugging the debugger. + */ +Debugger.Script.prototype.toString = function() { + let output = ""; + if (this.url) { + output += this.url; + } + if (typeof this.startLine != "undefined") { + output += ":" + this.startLine; + if (this.lineCount && this.lineCount > 1) { + output += "-" + (this.startLine + this.lineCount - 1); + } + } + if (this.strictMode) { + output += ":strict"; + } + return output; +}; + +/** + * Helper property for quickly getting to the line number a stack frame is + * currently paused at. + */ +Object.defineProperty(Debugger.Frame.prototype, "line", { + configurable: true, + get: function() { + if (this.script) { + return this.script.getOffsetLine(this.offset); + } else { + return null; + } + } +}); + + +/** + * Creates an actor for handling chrome debugging. ChromeDebuggerActor is a + * thin wrapper over ThreadActor, slightly changing some of its behavior. + * + * @param aConnection object + * The DebuggerServerConnection with which this ChromeDebuggerActor + * is associated. (Currently unused, but required to make this + * constructor usable with addGlobalActor.) + * + * @param aHooks object + * An object with preNest and postNest methods for calling when entering + * and exiting a nested event loop and also addToParentPool and + * removeFromParentPool methods for handling the lifetime of actors that + * will outlive the thread, like breakpoints. + */ +function ChromeDebuggerActor(aConnection, aHooks) +{ + ThreadActor.call(this, aHooks); +} + +ChromeDebuggerActor.prototype = Object.create(ThreadActor.prototype); + +update(ChromeDebuggerActor.prototype, { + constructor: ChromeDebuggerActor, + + // A constant prefix that will be used to form the actor ID by the server. + actorPrefix: "chromeDebugger", + + /** + * Override the eligibility check for scripts and sources to make sure every + * script and source with a URL is stored when debugging chrome. + */ + _allowSource: function(aSourceURL) !!aSourceURL, + + /** + * An object that will be used by ThreadActors to tailor their behavior + * depending on the debugging context being required (chrome or content). + * The methods that this object provides must be bound to the ThreadActor + * before use. + */ + globalManager: { + findGlobals: function CDA_findGlobals() { + // Add every global known to the debugger as debuggee. + this.dbg.addAllGlobalsAsDebuggees(); + }, + + /** + * A function that the engine calls when a new global object has been + * created. + * + * @param aGlobal Debugger.Object + * The new global object that was created. + */ + onNewGlobal: function CDA_onNewGlobal(aGlobal) { + this.addDebuggee(aGlobal); + // Notify the client. + this.conn.send({ + from: this.actorID, + type: "newGlobal", + // TODO: after bug 801084 lands see if we need to JSONify this. + hostAnnotations: aGlobal.hostAnnotations + }); + } + } +}); + + +/** + * Manages the sources for a thread. Handles source maps, locations in the + * sources, etc for ThreadActors. + */ +function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate, + aOnNewSource) { + this._thread = aThreadActor; + this._useSourceMaps = aUseSourceMaps; + this._allow = aAllowPredicate; + this._onNewSource = aOnNewSource; + + // source map URL --> promise of SourceMapConsumer + this._sourceMaps = Object.create(null); + // generated source url --> promise of SourceMapConsumer + this._sourceMapsByGeneratedSource = Object.create(null); + // original source url --> promise of SourceMapConsumer + this._sourceMapsByOriginalSource = Object.create(null); + // source url --> SourceActor + this._sourceActors = Object.create(null); + // original url --> generated url + this._generatedUrlsByOriginalUrl = Object.create(null); +} + +/** + * Must be a class property because it needs to persist across reloads, same as + * the breakpoint store. + */ +ThreadSources._blackBoxedSources = new Set(); + +ThreadSources.prototype = { + /** + * Return the source actor representing |aURL|, creating one if none + * exists already. Returns null if |aURL| is not allowed by the 'allow' + * predicate. + * + * Right now this takes a URL, but in the future it should + * take a Debugger.Source. See bug 637572. + * + * @param String aURL + * The source URL. + * @param optional SourceMapConsumer aSourceMap + * The source map that introduced this source, if any. + * @returns a SourceActor representing the source at aURL or null. + */ + source: function TS_source(aURL, aSourceMap=null) { + if (!this._allow(aURL)) { + return null; + } + + if (aURL in this._sourceActors) { + return this._sourceActors[aURL]; + } + + let actor = new SourceActor(aURL, this._thread, aSourceMap); + this._thread.threadLifetimePool.addActor(actor); + this._sourceActors[aURL] = actor; + try { + this._onNewSource(actor); + } catch (e) { + reportError(e); + } + return actor; + }, + + /** + * Return a promise of an array of source actors representing all the + * sources of |aScript|. + * + * If source map handling is enabled and |aScript| has a source map, then + * use it to find all of |aScript|'s *original* sources; return a promise + * of an array of source actors for those. + */ + sourcesForScript: function TS_sourcesForScript(aScript) { + if (!this._useSourceMaps || !aScript.sourceMapURL) { + return resolve([this.source(aScript.url)].filter(isNotNull)); + } + + return this.sourceMap(aScript) + .then((aSourceMap) => { + return [ + this.source(s, aSourceMap) for (s of aSourceMap.sources) + ]; + }) + .then(null, (e) => { + reportError(e); + delete this._sourceMaps[this._normalize(aScript.sourceMapURL, aScript.url)]; + delete this._sourceMapsByGeneratedSource[aScript.url]; + return [this.source(aScript.url)]; + }) + .then(function (aSources) { + return aSources.filter(isNotNull); + }); + }, + + /** + * Return a promise of a SourceMapConsumer for the source map for + * |aScript|; if we already have such a promise extant, return that. + * |aScript| must have a non-null sourceMapURL. + */ + sourceMap: function TS_sourceMap(aScript) { + if (aScript.url in this._sourceMapsByGeneratedSource) { + return this._sourceMapsByGeneratedSource[aScript.url]; + } + dbg_assert(aScript.sourceMapURL); + let sourceMapURL = this._normalize(aScript.sourceMapURL, aScript.url); + let map = this._fetchSourceMap(sourceMapURL) + .then((aSourceMap) => { + for (let s of aSourceMap.sources) { + this._generatedUrlsByOriginalUrl[s] = aScript.url; + this._sourceMapsByOriginalSource[s] = resolve(aSourceMap); + } + return aSourceMap; + }); + this._sourceMapsByGeneratedSource[aScript.url] = map; + return map; + }, + + /** + * Return a promise of a SourceMapConsumer for the source map located at + * |aAbsSourceMapURL|, which must be absolute. If there is already such a + * promise extant, return it. + */ + _fetchSourceMap: function TS__fetchSourceMap(aAbsSourceMapURL) { + if (aAbsSourceMapURL in this._sourceMaps) { + return this._sourceMaps[aAbsSourceMapURL]; + } else { + let promise = fetch(aAbsSourceMapURL).then((rawSourceMap) => { + let map = new SourceMapConsumer(rawSourceMap); + let base = aAbsSourceMapURL.replace(/\/[^\/]+$/, '/'); + if (base.indexOf("data:") !== 0) { + map.sourceRoot = map.sourceRoot + ? this._normalize(map.sourceRoot, base) + : base; + } + return map; + }); + this._sourceMaps[aAbsSourceMapURL] = promise; + return promise; + } + }, + + /** + * Returns a promise of the location in the original source if the source is + * source mapped, otherwise a promise of the same location. + * + * TODO bug 637572: take/return a column + */ + getOriginalLocation: function TS_getOriginalLocation(aSourceUrl, aLine) { + if (aSourceUrl in this._sourceMapsByGeneratedSource) { + return this._sourceMapsByGeneratedSource[aSourceUrl] + .then(function (aSourceMap) { + let { source, line } = aSourceMap.originalPositionFor({ + source: aSourceUrl, + line: aLine, + column: Infinity + }); + return { + url: source, + line: line + }; + }); + } + + // No source map + return resolve({ + url: aSourceUrl, + line: aLine + }); + }, + + /** + * Returns a promise of the location in the generated source corresponding to + * the original source and line given. + * + * When we pass a script S representing generated code to |sourceMap|, + * above, that returns a promise P. The process of resolving P populates + * the tables this function uses; thus, it won't know that S's original + * source URLs map to S until P is resolved. + * + * TODO bug 637572: take/return a column + */ + getGeneratedLocation: function TS_getGeneratedLocation(aSourceUrl, aLine) { + if (aSourceUrl in this._sourceMapsByOriginalSource) { + return this._sourceMapsByOriginalSource[aSourceUrl] + .then((aSourceMap) => { + let { line } = aSourceMap.generatedPositionFor({ + source: aSourceUrl, + line: aLine, + column: Infinity + }); + return { + url: this._generatedUrlsByOriginalUrl[aSourceUrl], + line: line + }; + }); + } + + // No source map + return resolve({ + url: aSourceUrl, + line: aLine + }); + }, + + /** + * Returns true if URL for the given source is black boxed. + * + * @param aURL String + * The URL of the source which we are checking whether it is black + * boxed or not. + */ + isBlackBoxed: function TS_isBlackBoxed(aURL) { + return ThreadSources._blackBoxedSources.has(aURL); + }, + + /** + * Add the given source URL to the set of sources that are black boxed. If the + * thread is currently paused and we are black boxing the yougest frame's + * source, this will force a step. + * + * @param aURL String + * The URL of the source which we are black boxing. + */ + blackBox: function TS_blackBox(aURL) { + ThreadSources._blackBoxedSources.add(aURL); + }, + + /** + * Remove the given source URL to the set of sources that are black boxed. + * + * @param aURL String + * The URL of the source which we are no longer black boxing. + */ + unblackBox: function TS_unblackBox(aURL) { + ThreadSources._blackBoxedSources.delete(aURL); + }, + + /** + * Normalize multiple relative paths towards the base paths on the right. + */ + _normalize: function TS__normalize(...aURLs) { + dbg_assert(aURLs.length > 1); + let base = Services.io.newURI(aURLs.pop(), null, null); + let url; + while ((url = aURLs.pop())) { + base = Services.io.newURI(url, null, base); + } + return base.spec; + }, + + iter: function TS_iter() { + for (let url in this._sourceActors) { + yield this._sourceActors[url]; + } + } +}; + +// Utility functions. + +/** + * Utility function for updating an object with the properties of another + * object. + * + * @param aTarget Object + * The object being updated. + * @param aNewAttrs Object + * The new attributes being set on the target. + */ +function update(aTarget, aNewAttrs) { + for (let key in aNewAttrs) { + let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key); + + if (desc) { + Object.defineProperty(aTarget, key, desc); + } + } +} + +/** + * Returns true if its argument is not null. + */ +function isNotNull(aThing) { + return aThing !== null; +} + +/** + * Performs a request to load the desired URL and returns a promise. + * + * @param aURL String + * The URL we will request. + * @returns Promise + * A promise of the document at that URL, as a string. + * + * XXX: It may be better to use nsITraceableChannel to get to the sources + * without relying on caching when we can (not for eval, etc.): + * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ + */ +function fetch(aURL, aOptions={ loadFromCache: true }) { + let deferred = defer(); + let scheme; + let url = aURL.split(" -> ").pop(); + let charset; + let filePath = url; + // try { + // scheme = Services.io.extractScheme(url); + // } catch (e) { + // In the xpcshell tests, the script url is the absolute path of the test + // file, which will make a malformed URI error be thrown. Add the file + // scheme prefix ourselves. + url = "file://" + url; + // scheme = Services.io.extractScheme(url); + // } + scheme = "file"; + + switch (scheme) { + case "file": + case "chrome": + case "resource": + try { + // NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) { + // if (!Components.isSuccessCode(aStatus)) { + // deferred.reject("Request failed: " + url); + // return; + // } + let cc = globalDebuggee.cc; + let fileUtils = cc.FileUtils.getInstance(); + let source = fileUtils.getStringFromFile(filePath);//NetUtil.readInputStreamToString(aStream, aStream.available()); + if (!source) + { + deferred.reject("Request failed: " + url); + } + else + { + deferred.resolve(source); + } + // aStream.close(); + // }); + } catch (ex) { + deferred.reject("Request failed: " + url); + } + break; + + default: + let channel; + try { + channel = Services.io.newChannel(url, null, null); + } catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") { + // On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but + // newChannel won't be able to handle it. + url = "file:///" + url; + channel = Services.io.newChannel(url, null, null); + } + let chunks = []; + let streamListener = { + onStartRequest: function(aRequest, aContext, aStatusCode) { + if (!Components.isSuccessCode(aStatusCode)) { + deferred.reject("Request failed: " + url); + } + }, + onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) { + chunks.push(NetUtil.readInputStreamToString(aStream, aCount)); + }, + onStopRequest: function(aRequest, aContext, aStatusCode) { + if (!Components.isSuccessCode(aStatusCode)) { + deferred.reject("Request failed: " + url); + return; + } + + charset = channel.contentCharset; + deferred.resolve(chunks.join("")); + } + }; + + channel.loadFlags = aOptions.loadFromCache + ? channel.LOAD_FROM_CACHE + : channel.LOAD_BYPASS_CACHE; + channel.asyncOpen(streamListener, null); + break; + } + + return deferred.promise.then(function (source) { + return convertToUnicode(source, charset); + }); +} + +/** + * Convert a given string, encoded in a given character set, to unicode. + * + * @param string aString + * A string. + * @param string aCharset + * A character set. + */ +function convertToUnicode(aString, aCharset=null) { + // Decoding primitives. + // let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + // .createInstance(Ci.nsIScriptableUnicodeConverter); + // try { + // converter.charset = aCharset || "UTF-8"; + // return converter.ConvertToUnicode(aString); + // } catch(e) { + return aString; + // } +} + +/** + * Report the given error in the error console and to stdout. + */ +function reportError(aError) { + // Cu.reportError(aError); + dumpn(aError.message + ":\n" + aError.stack); +} diff --git a/scripting/javascript/bindings/js/debugger/actors/string.js b/scripting/javascript/bindings/js/debugger/actors/string.js new file mode 100644 index 0000000000..8fc1eda94e --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/string.js @@ -0,0 +1,145 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let {Cu} = require("chrome"); +let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); + +let promise = require("sdk/core/promise"); +let {Class} = require("sdk/core/heritage"); + +let protocol = require("devtools/server/protocol"); +let {method, Arg, Option, RetVal} = protocol; + +exports.LongStringActor = protocol.ActorClass({ + typeName: "longstractor", + + initialize: function(conn, str) { + protocol.Actor.prototype.initialize.call(this, conn); + this.str = str; + this.short = (this.str.length < DebuggerServer.LONG_STRING_LENGTH); + }, + + destroy: function() { + this.str = null; + protocol.Actor.prototype.destroy.call(this); + }, + + form: function() { + if (this.short) { + return this.str; + } + return { + type: "longString", + actor: this.actorID, + length: this.str.length, + initial: this.str.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH) + } + }, + + substring: method(function(start, end) { + return promise.resolve(this.str.substring(start, end)); + }, { + request: { + start: Arg(0), + end: Arg(1) + }, + response: { substring: RetVal() }, + }), + + release: method(function() { }, { release: true }) +}); + +/** + * When a LongString on the server is short enough to be passed + * as a full string, the client will get a ShortLongString instead of + * a LongStringFront. Its API should match. + * + * I'm very proud of this name. + */ +exports.ShortLongString = Class({ + initialize: function(str) { + this.str = str; + }, + + get length() { return this.str.length; }, + get initial() { return this.str; }, + string: function() { return promise.resolve(this.str) }, + + substring: function(start, end) { + return promise.resolve(this.str.substring(start, end)); + }, + + release: function() { + this.str = null; + return promise.resolve(undefined); + } +}) + +exports.LongStringFront = protocol.FrontClass(exports.LongStringActor, { + initialize: function(client, form) { + // Don't give the form by default, because we're being tricky and it might just + // be a string. + protocol.Front.prototype.initialize.call(this, client, null); + this.form(form); + }, + + destroy: function() { + this.initial = null; + this.length = null; + this.strPromise = null; + protocol.Front.prototype.destroy.call(this); + }, + + form: function(form) { + this.actorID = form.actorID; + this.initial = form.initial; + this.length = form.length; + }, + + string: function() { + if (!this.strPromise) { + let promiseRest = (thusFar) => { + if (thusFar.length === this.length) + return promise.resolve(thusFar); + else { + return this.substring(thusFar.length, + thusFar.length + DebuggerServer.LONG_STRING_READ_LENGTH) + .then((next) => promiseRest(thusFar + next)); + } + } + + this.strPromise = promiseRest(this.initial); + } + return this.strPromise; + } +}); + +// The long string actor needs some custom marshalling, because it is sometimes +// returned as a primitive rather than a complete form. + +let stringActorType = protocol.types.getType("longstractor"); +protocol.types.addType("longstring", { + _actor: true, + write: (value, context, detail) => { + if (!(context instanceof protocol.Actor)) { + throw Error("Passing a longstring as an argument isn't supported."); + } + if (value.short) { + return value.str; + } else { + return stringActorType.write(value, context, detail); + } + }, + read: (value, context, detail) => { + if (context instanceof protocol.Actor) { + throw Error("Passing a longstring as an argument isn't supported."); + } + if (typeof(value) === "string") { + return exports.ShortLongString(value); + } + return stringActorType.read(value, context, detail); + } +}); diff --git a/scripting/javascript/bindings/js/debugger/actors/styleeditor.js b/scripting/javascript/bindings/js/debugger/actors/styleeditor.js new file mode 100644 index 0000000000..d4ef50186d --- /dev/null +++ b/scripting/javascript/bindings/js/debugger/actors/styleeditor.js @@ -0,0 +1,740 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let Cc = Components.classes; +let Ci = Components.interfaces; +let Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + +let TRANSITION_CLASS = "moz-styleeditor-transitioning"; +let TRANSITION_DURATION_MS = 500; +let TRANSITION_RULE = "\ +:root.moz-styleeditor-transitioning, :root.moz-styleeditor-transitioning * {\ +transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \ +transition-delay: 0ms !important;\ +transition-timing-function: ease-out !important;\ +transition-property: all !important;\ +}"; + +let LOAD_ERROR = "error-load"; + +/** + * Creates a StyleEditorActor. StyleEditorActor provides remote access to the + * built-in style editor module. + */ +function StyleEditorActor(aConnection, aParentActor) +{ + this.conn = aConnection; + this._onDocumentLoaded = this._onDocumentLoaded.bind(this); + this._onSheetLoaded = this._onSheetLoaded.bind(this); + + if (aParentActor instanceof BrowserTabActor && + aParentActor.browser instanceof Ci.nsIDOMWindow) { + this._window = aParentActor.browser; + } + else if (aParentActor instanceof BrowserTabActor && + aParentActor.browser instanceof Ci.nsIDOMElement) { + this._window = aParentActor.browser.contentWindow; + } + else { + this._window = Services.wm.getMostRecentWindow("navigator:browser"); + } + + // keep a map of sheets-to-actors so we don't create two actors for one sheet + this._sheets = new Map(); + + this._actorPool = new ActorPool(this.conn); + this.conn.addActorPool(this._actorPool); +} + +StyleEditorActor.prototype = { + /** + * Actor pool for all of the actors we send to the client. + */ + _actorPool: null, + + /** + * The debugger server connection instance. + */ + conn: null, + + /** + * The content window we work with. + */ + get win() this._window, + + /** + * The current content document of the window we work with. + */ + get doc() this._window.document, + + /** + * A window object, usually the browser window + */ + _window: null, + + actorPrefix: "styleEditor", + + form: function() + { + return { actor: this.actorID }; + }, + + /** + * Destroy the current StyleEditorActor instance. + */ + disconnect: function() + { + if (this._observer) { + this._observer.disconnect(); + delete this._observer; + } + + this._sheets.clear(); + + this.conn.removeActorPool(this._actorPool); + this._actorPool = null; + this.conn = this._window = null; + }, + + /** + * Release an actor from our actor pool. + */ + releaseActor: function(actor) + { + if (this._actorPool) { + this._actorPool.removeActor(actor.actorID); + } + }, + + /** + * Get the BaseURI for the document. + * + * @return {object} JSON message to with BaseURI + */ + onGetBaseURI: function() { + return { baseURI: this.doc.baseURIObject }; + }, + + /** + * Called when target navigates to a new document. + * Adds load listeners to document. + */ + onNewDocument: function() { + // delete previous document's actors + this._clearStyleSheetActors(); + + // Note: listening for load won't be necessary once + // https://bugzilla.mozilla.org/show_bug.cgi?id=839103 is fixed + if (this.doc.readyState == "complete") { + this._onDocumentLoaded(); + } + else { + this.win.addEventListener("load", this._onDocumentLoaded, false); + } + return {}; + }, + + /** + * Event handler for document loaded event. Add actor for each stylesheet + * and send an event notifying of the load + */ + _onDocumentLoaded: function(event) { + if (event) { + this.win.removeEventListener("load", this._onDocumentLoaded, false); + } + + let documents = [this.doc]; + var forms = []; + for (let doc of documents) { + let sheetForms = this._addStyleSheets(doc.styleSheets); + forms = forms.concat(sheetForms); + // Recursively handle style sheets of the documents in iframes. + for (let iframe of doc.getElementsByTagName("iframe")) { + documents.push(iframe.contentDocument); + } + } + + this.conn.send({ + from: this.actorID, + type: "documentLoad", + styleSheets: forms + }); + }, + + /** + * Add all the stylesheets to the map and create an actor + * for each one if not already created. Send event that there + * are new stylesheets. + * + * @param {[DOMStyleSheet]} styleSheets + * Stylesheets to add + * @return {[object]} + * Array of forms for each StyleSheetActor created + */ + _addStyleSheets: function(styleSheets) + { + let sheets = []; + for (let i = 0; i < styleSheets.length; i++) { + let styleSheet = styleSheets[i]; + sheets.push(styleSheet); + + // Get all sheets, including imported ones + let imports = this._getImported(styleSheet); + sheets = sheets.concat(imports); + } + + let forms = sheets.map((sheet) => { + let actor = this._createStyleSheetActor(sheet); + return actor.form(); + }); + + return forms; + }, + + /** + * Get all the stylesheets @imported from a stylesheet. + * + * @param {DOMStyleSheet} styleSheet + * Style sheet to search + * @return {array} + * All the imported stylesheets + */ + _getImported: function(styleSheet) { + let imported = []; + + for (let i = 0; i < styleSheet.cssRules.length; i++) { + let rule = styleSheet.cssRules[i]; + if (rule.type == Ci.nsIDOMCSSRule.IMPORT_RULE) { + // Associated styleSheet may be null if it has already been seen due to + // duplicate @imports for the same URL. + if (!rule.styleSheet) { + continue; + } + imported.push(rule.styleSheet); + + // recurse imports in this stylesheet as well + imported = imported.concat(this._getImported(rule.styleSheet)); + } + else if (rule.type != Ci.nsIDOMCSSRule.CHARSET_RULE) { + // @import rules must precede all others except @charset + break; + } + } + return imported; + }, + + /** + * Create a new actor for a style sheet, if it hasn't + * already been created, and return it. + * + * @param {DOMStyleSheet} aStyleSheet + * The style sheet to create an actor for. + * @return {StyleSheetActor} + * The actor for this style sheet + */ + _createStyleSheetActor: function(aStyleSheet) + { + if (this._sheets.has(aStyleSheet)) { + return this._sheets.get(aStyleSheet); + } + let actor = new StyleSheetActor(aStyleSheet, this); + this._actorPool.addActor(actor); + this._sheets.set(aStyleSheet, actor); + return actor; + }, + + /** + * Clear all the current stylesheet actors in map. + */ + _clearStyleSheetActors: function() { + for (let actor in this._sheets) { + this.releaseActor(this._sheets[actor]); + } + this._sheets.clear(); + }, + + /** + * Get the actors of all the stylesheets in the current document. + * + * @return {object} JSON message with the stylesheet actors' forms + */ + onGetStyleSheets: function() { + let forms = this._addStyleSheets(this.doc.styleSheets); + return { "styleSheets": forms }; + }, + + /** + * Handler for style sheet loading event. Add + * a new actor for the sheet and notify. + * + * @param {Event} event + */ + _onSheetLoaded: function(event) { + let style = event.target; + style.removeEventListener("load", this._onSheetLoaded, false); + + let actor = this._createStyleSheetActor(style.sheet); + this._notifyStyleSheetsAdded([actor.form()]); + }, + + /** + * Create a new style sheet in the document with the given text. + * Return an actor for it. + * + * @param {object} request + * Debugging protocol request object, with 'text property' + * @return {object} + * Object with 'styelSheet' property for form on new actor. + */ + onNewStyleSheet: function(request) { + let parent = this.doc.documentElement; + let style = this.doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); + style.setAttribute("type", "text/css"); + + if (request.text) { + style.appendChild(this.doc.createTextNode(request.text)); + } + parent.appendChild(style); + + let actor = this._createStyleSheetActor(style.sheet); + return { styleSheet: actor.form() }; + } +}; + +/** + * The request types this actor can handle. + */ +StyleEditorActor.prototype.requestTypes = { + "getStyleSheets": StyleEditorActor.prototype.onGetStyleSheets, + "newStyleSheet": StyleEditorActor.prototype.onNewStyleSheet, + "getBaseURI": StyleEditorActor.prototype.onGetBaseURI, + "newDocument": StyleEditorActor.prototype.onNewDocument +}; + + +function StyleSheetActor(aStyleSheet, aParentActor) { + this.styleSheet = aStyleSheet; + this.parentActor = aParentActor; + + // text and index are unknown until source load + this.text = null; + this._styleSheetIndex = -1; + + this._transitionRefCount = 0; + + this._onSourceLoad = this._onSourceLoad.bind(this); + this._notifyError = this._notifyError.bind(this); + + // if this sheet has an @import, then it's rules are loaded async + let ownerNode = this.styleSheet.ownerNode; + if (ownerNode) { + let onSheetLoaded = function(event) { + ownerNode.removeEventListener("load", onSheetLoaded, false); + this._notifyPropertyChanged("ruleCount"); + }.bind(this); + + ownerNode.addEventListener("load", onSheetLoaded, false); + } +} + +StyleSheetActor.prototype = { + actorPrefix: "stylesheet", + + toString: function() { + return "[StyleSheetActor " + this.actorID + "]"; + }, + + disconnect: function() { + this.parentActor.releaseActor(this); + }, + + /** + * Window of target + */ + get win() { + return this.parentActor._window; + }, + + /** + * Document of target. + */ + get doc() { + return this.win.document; + }, + + /** + * Retrieve the index (order) of stylesheet in the document. + * + * @return number + */ + get styleSheetIndex() + { + if (this._styleSheetIndex == -1) { + for (let i = 0; i < this.doc.styleSheets.length; i++) { + if (this.doc.styleSheets[i] == this.styleSheet) { + this._styleSheetIndex = i; + break; + } + } + } + return this._styleSheetIndex; + }, + + /** + * Get the current state of the actor + * + * @return {object} + * With properties of the underlying stylesheet, plus 'text', + * 'styleSheetIndex' and 'parentActor' if it's @imported + */ + form: function() { + let form = { + actor: this.actorID, // actorID is set when this actor is added to a pool + href: this.styleSheet.href, + disabled: this.styleSheet.disabled, + title: this.styleSheet.title, + styleSheetIndex: this.styleSheetIndex, + text: this.text + } + + // get parent actor if this sheet was @imported + let parent = this.styleSheet.parentStyleSheet; + if (parent) { + form.parentActor = this.parentActor._sheets.get(parent); + } + + try { + form.ruleCount = this.styleSheet.cssRules.length; + } + catch(e) { + // stylesheet had an @import rule that wasn't loaded yet + } + + return form; + }, + + /** + * Toggle the disabled property of the style sheet + * + * @return {object} + * 'disabled' - the disabled state after toggling. + */ + onToggleDisabled: function() { + this.styleSheet.disabled = !this.styleSheet.disabled; + this._notifyPropertyChanged("disabled"); + + return { disabled: this.styleSheet.disabled }; + }, + + /** + * Send an event notifying that a property of the stylesheet + * has changed. + * + * @param {string} property + * Name of the changed property + */ + _notifyPropertyChanged: function(property) { + this.conn.send({ + from: this.actorID, + type: "propertyChange-" + this.actorID, + property: property, + value: this.form()[property] + }) + }, + + /** + * Send an event notifying that an error has occured + * + * @param {string} message + * Error message + */ + _notifyError: function(message) { + this.conn.send({ + from: this.actorID, + type: "error-" + this.actorID, + errorMessage: message + }); + }, + + /** + * Handler for event when the style sheet's full text has been + * loaded from its source. + * + * @param {string} source + * Text of the style sheet + * @param {[type]} charset + * Optional charset of the source + */ + _onSourceLoad: function(source, charset) { + this.text = this._decodeCSSCharset(source, charset || ""); + + this.conn.send({ + from: this.actorID, + type: "sourceLoad-" + this.actorID, + source: this.text + }); + }, + + /** + * Fetch the source of the style sheet from its URL + */ + onFetchSource: function() { + if (!this.styleSheet.href) { + // this is an inline - - -
- -
- - diff --git a/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro b/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro deleted file mode 100644 index 1678596819..0000000000 --- a/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro +++ /dev/null @@ -1,128 +0,0 @@ - -include(../../../../cocos2dx/proj.qt5/common.pri) - -TARGET = cocos2dx_TestCpp - -INCLUDEPATH += .. -INCLUDEPATH += ../Classes - -SOURCES += main.cpp -SOURCES += ../Classes/AccelerometerTest/AccelerometerTest.cpp \ - ../Classes/ActionManagerTest/ActionManagerTest.cpp \ - ../Classes/ActionsEaseTest/ActionsEaseTest.cpp \ - ../Classes/ActionsProgressTest/ActionsProgressTest.cpp \ - ../Classes/ActionsTest/ActionsTest.cpp \ - ../Classes/Box2DTest/Box2dTest.cpp \ - ../Classes/Box2DTestBed/Box2dView.cpp \ - ../Classes/Box2DTestBed/GLES-Render.cpp \ - ../Classes/Box2DTestBed/Test.cpp \ - ../Classes/Box2DTestBed/TestEntries.cpp \ - ../Classes/BugsTest/Bug-1159.cpp \ - ../Classes/BugsTest/Bug-1174.cpp \ - ../Classes/BugsTest/Bug-350.cpp \ - ../Classes/BugsTest/Bug-422.cpp \ - ../Classes/BugsTest/Bug-458/Bug-458.cpp \ - ../Classes/BugsTest/Bug-458/QuestionContainerSprite.cpp \ - ../Classes/BugsTest/Bug-624.cpp \ - ../Classes/BugsTest/Bug-886.cpp \ - ../Classes/BugsTest/Bug-899.cpp \ - ../Classes/BugsTest/Bug-914.cpp \ - ../Classes/BugsTest/BugsTest.cpp \ - ../Classes/ChipmunkTest/ChipmunkTest.cpp \ - ../Classes/ClickAndMoveTest/ClickAndMoveTest.cpp \ - ../Classes/ClippingNodeTest/ClippingNodeTest.cpp \ - ../Classes/CocosDenshionTest/CocosDenshionTest.cpp \ - ../Classes/CurlTest/CurlTest.cpp \ - ../Classes/CurrentLanguageTest/CurrentLanguageTest.cpp \ - ../Classes/DrawPrimitivesTest/DrawPrimitivesTest.cpp \ - ../Classes/EffectsAdvancedTest/EffectsAdvancedTest.cpp \ - ../Classes/EffectsTest/EffectsTest.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/CocosBuilderTest.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/HelloCocosBuilder/HelloCocosBuilderLayer.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/MenuTest/MenuTestLayer.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/TestHeader/TestHeaderLayer.cpp \ - ../Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlButtonTest/CCControlButtonTest.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlColourPicker/CCControlColourPickerTest.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlScene.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSceneManager.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSliderTest/CCControlSliderTest.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSwitchTest/CCControlSwitchTest.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlPotentiometerTest/CCControlPotentiometerTest.cpp \ - ../Classes/ExtensionsTest/ControlExtensionTest/CCControlStepperTest/CCControlStepperTest.cpp \ - ../Classes/ExtensionsTest/TableViewTest/TableViewTestScene.cpp \ - ../Classes/ExtensionsTest/TableViewTest/CustomTableViewCell.cpp \ - ../Classes/ExtensionsTest/ExtensionsTest.cpp \ - ../Classes/ExtensionsTest/NotificationCenterTest/NotificationCenterTest.cpp \ - ../Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/ComponentsTestScene.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/EnemyController.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/GameOverScene.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/PlayerController.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/ProjectileController.cpp \ - ../Classes/ExtensionsTest/ComponentsTest/SceneController.cpp \ - ../Classes/ExtensionsTest/ArmatureTest/ArmatureScene.cpp \ - ../Classes/ExtensionsTest/Scale9SpriteTest/Scale9SpriteTest.cpp \ - ../Classes/NewEventDispatcherTest/NewEventDispatcherTest.cpp \ - ../Classes/FontTest/FontTest.cpp \ - ../Classes/IntervalTest/IntervalTest.cpp \ - ../Classes/KeyboardTest/KeyboardTest.cpp \ - ../Classes/KeypadTest/KeypadTest.cpp \ - ../Classes/LabelTest/LabelTest.cpp \ - ../Classes/LayerTest/LayerTest.cpp \ - ../Classes/MenuTest/MenuTest.cpp \ - ../Classes/MotionStreakTest/MotionStreakTest.cpp \ - ../Classes/MutiTouchTest/MutiTouchTest.cpp \ - ../Classes/NodeTest/NodeTest.cpp \ - ../Classes/ParallaxTest/ParallaxTest.cpp \ - ../Classes/ParticleTest/ParticleTest.cpp \ - ../Classes/PerformanceTest/PerformanceNodeChildrenTest.cpp \ - ../Classes/PerformanceTest/PerformanceParticleTest.cpp \ - ../Classes/PerformanceTest/PerformanceSpriteTest.cpp \ - ../Classes/PerformanceTest/PerformanceTest.cpp \ - ../Classes/PerformanceTest/PerformanceTextureTest.cpp \ - ../Classes/PerformanceTest/PerformanceTouchesTest.cpp \ - ../Classes/RenderTextureTest/RenderTextureTest.cpp \ - ../Classes/RotateWorldTest/RotateWorldTest.cpp \ - ../Classes/SceneTest/SceneTest.cpp \ - ../Classes/SchedulerTest/SchedulerTest.cpp \ - ../Classes/ShaderTest/ShaderTest.cpp \ - ../Classes/SpriteTest/SpriteTest.cpp \ - ../Classes/TextInputTest/TextInputTest.cpp \ - ../Classes/Texture2dTest/Texture2dTest.cpp \ - ../Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp \ - ../Classes/TextureCacheTest/TextureCacheTest.cpp \ - ../Classes/TileMapTest/TileMapTest.cpp \ - ../Classes/TouchesTest/Ball.cpp \ - ../Classes/TouchesTest/Paddle.cpp \ - ../Classes/TouchesTest/TouchesTest.cpp \ - ../Classes/TransitionsTest/TransitionsTest.cpp \ - ../Classes/UserDefaultTest/UserDefaultTest.cpp \ - ../Classes/ZwoptexTest/ZwoptexTest.cpp \ - ../Classes/FileUtilsTest/FileUtilsTest.cpp \ - ../Classes/SpineTest/SpineTest.cpp \ - ../Classes/DataVisitorTest/DataVisitorTest.cpp \ - ../Classes/ConfigurationTest/ConfigurationTest.cpp \ - ../Classes/controller.cpp \ - ../Classes/testBasic.cpp \ - ../Classes/AppDelegate.cpp \ - ../Classes/BaseTest.cpp \ - ../Classes/VisibleRect.cpp - -LIBS += $${LINK_AGAINST_COCOS2DX} -LIBS += $${LINK_AGAINST_COCOSDENSHION} -LIBS += $${LINK_AGAINST_COCOSEXTENSION} - -INSTALLS += target -target.path = /opt/$${TARGET} - -INSTALLS += desktop -desktop.files = $${TARGET}.desktop -desktop.path = $${DESKTOP_INSTALL_DIR} - -INSTALLS += resources -resources.files = icon.png ../Resources -resources.path = /opt/$${TARGET} - diff --git a/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop b/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop deleted file mode 100644 index 8447988c7f..0000000000 --- a/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop +++ /dev/null @@ -1,5 +0,0 @@ -[Desktop Entry] -Type=Application -Name=Cocos2D-X -Icon=/opt/cocos2dx_TestCpp/icon.png -Exec=/opt/cocos2dx_TestCpp/cocos2dx_TestCpp diff --git a/samples/Cpp/TestCpp/proj.qt5/main.cpp b/samples/Cpp/TestCpp/proj.qt5/main.cpp deleted file mode 100644 index 87fe8873df..0000000000 --- a/samples/Cpp/TestCpp/proj.qt5/main.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "../Classes/AppDelegate.h" -#include "cocos2d.h" -#include "CCEGLView.h" - -#include -#include -#include -#include - -USING_NS_CC; - -int main(int argc, char **argv) -{ - // create the application instance - AppDelegate app; - auto eglView = CCEGLView::sharedOpenGLView(); - eglView->setFrameSize(800, 480); - return CCApplication::sharedApplication()->run(); -} diff --git a/samples/Cpp/TestCpp/proj.tizen/.cproject b/samples/Cpp/TestCpp/proj.tizen/.cproject deleted file mode 100644 index 9cb31d8072..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/.cproject +++ /dev/null @@ -1,701 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Cpp/TestCpp/proj.tizen/.project b/samples/Cpp/TestCpp/proj.tizen/.project deleted file mode 100644 index ad264e16ca..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/.project +++ /dev/null @@ -1,106 +0,0 @@ - - - proj.tizen - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - sbi-make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/${ProjName}/Debug-Tizen-Emulator} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - true - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - org.tizen.nativecpp.apichecker.core.builder - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - org.tizen.nativecpp.apichecker.core.tizenCppNature - - - - src/Classes - 2 - PARENT-1-PROJECT_LOC/Classes - - - - - 1372993495655 - - 26 - - org.eclipse.ui.ide.multiFilter - 1.0-projectRelativePath-matches-false-false-*/.tpk - - - - diff --git a/samples/Cpp/TestCpp/proj.tizen/README.mdown b/samples/Cpp/TestCpp/proj.tizen/README.mdown deleted file mode 100644 index 68e93e99e0..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/README.mdown +++ /dev/null @@ -1,6 +0,0 @@ -TestCpp for Tizen -================== - - * Create Tizen IDE workspace in cocos2d-x/samples/Cpp/TestCpp - * Import proj.tizen - * Copy cocos2d-x/samples/Cpp/TestCpp/Resources/*.* to cocos2d-x/samples/Cpp/TestCpp/proj.tizen/res diff --git a/samples/Cpp/TestCpp/proj.tizen/data/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/inc/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/inc/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/lib/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/lib/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/manifest.xml b/samples/Cpp/TestCpp/proj.tizen/manifest.xml deleted file mode 100644 index 32976beeb6..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/manifest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - WMrZqguX0B - 1.0.0 - C++App - - true - - - 2.2 - - - - - - TestCpp - - - mainmenu.png - - - - - diff --git a/samples/Cpp/TestCpp/proj.tizen/res/.gitignore b/samples/Cpp/TestCpp/proj.tizen/res/.gitignore deleted file mode 100644 index 1d65afe366..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/res/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -#Do now ignore Marmalade icf files -!*.icf diff --git a/samples/Cpp/TestCpp/proj.tizen/res/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/res/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/shared/data/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/shared/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/shared/trusted/.gitkeep b/samples/Cpp/TestCpp/proj.tizen/shared/trusted/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Cpp/TestCpp/proj.tizen/src/TestCppEntry.cpp b/samples/Cpp/TestCpp/proj.tizen/src/TestCppEntry.cpp deleted file mode 100644 index 3ec1b2ae63..0000000000 --- a/samples/Cpp/TestCpp/proj.tizen/src/TestCppEntry.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -Copyright (c) 2013 cocos2d-x.org -Copyright (c) 2013 Lee, Jae-Hong - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -// -// This file contains the Tizen application entry point. -// -#include "../../Classes/AppDelegate.h" -#include "cocos2d.h" - -USING_NS_CC; -using namespace Tizen::Base; -using namespace Tizen::Base::Collection; - -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus - -void -ApplicationInitialized(void) -{ - AppDelegate* pAppDelegate = new AppDelegate; - - auto eglView = EGLView::getInstance(); - eglView->setFrameSize(1280, 720); - - Application::getInstance()->run(); -} - -// -// The entry function of Tizen application called by the operating system. -// -_EXPORT_ int -OspMain(int argc, char *pArgv[]) -{ - AppLog("Application started."); - ArrayList args(SingleObjectDeleter); - args.Construct(); - for (int i = 0; i < argc; i++) - { - args.Add(new (std::nothrow) Tizen::Base::String(pArgv[i])); - } - - OspApplication::SetApplicationInitializedCallback(ApplicationInitialized); - OspApplication::SetScreenOrientation(Tizen::Ui::ORIENTATION_LANDSCAPE); - result r = Tizen::App::Application::Execute(OspApplication::CreateInstance, &args); - TryLog(r == E_SUCCESS, "[%s] Application execution failed", GetErrorMessage(r)); - AppLog("Application finished."); - - return static_cast(r); -} -#ifdef __cplusplus -} -#endif // __cplusplus diff --git a/samples/Lua/HelloLua/proj.emscripten/Makefile b/samples/Lua/HelloLua/proj.emscripten/Makefile deleted file mode 100644 index 3cb02a4db5..0000000000 --- a/samples/Lua/HelloLua/proj.emscripten/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -EXECUTABLE = HelloLua - -COCOS_ROOT = ../../../.. -INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ - -I$(COCOS_ROOT)/scripting/lua/lua \ - -I$(COCOS_ROOT)/scripting/lua/tolua \ - -I$(COCOS_ROOT)/scripting/lua/cocos2dx_support \ - -I$(COCOS_ROOT)/extensions \ - -SOURCES = main.cpp ../Classes/AppDelegate.cpp - -SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so - -include $(COCOS_ROOT)/cocos2dx/proj.emscripten/cocos2dx.mk - -$(TARGET): $(OBJECTS) $(STATICLIBS) $(COCOS_LIBS) $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - cp -r ../../../../scripting/lua/script/ ../../../../samples/Lua/HelloLua/Resources - $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@ $(SHAREDLIBS) $(STATICLIBS) $(LIBS) - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@ - -$(OBJ_DIR)/%.o: %.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@ diff --git a/samples/Lua/HelloLua/proj.emscripten/main.cpp b/samples/Lua/HelloLua/proj.emscripten/main.cpp deleted file mode 100644 index 92b65bdca4..0000000000 --- a/samples/Lua/HelloLua/proj.emscripten/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "../Classes/AppDelegate.h" -#include "cocos2d.h" - -#include -#include -#include -#include - -USING_NS_CC; - -int main(int argc, char **argv) -{ - // create the application instance - AppDelegate app; - auto eglView = EGLView::getInstance(); - eglView->setFrameSize(960, 640); - return Application::getInstance()->run(); -} diff --git a/samples/Lua/HelloLua/proj.nacl/Makefile b/samples/Lua/HelloLua/proj.nacl/Makefile deleted file mode 100644 index 64ee13248e..0000000000 --- a/samples/Lua/HelloLua/proj.nacl/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -COCOS_ROOT = ../../../.. -COCOS2DX_PATH = $(COCOS_ROOT)/cocos2dx - -INCLUDES = -I.. \ - -I../Classes \ - -I$(COCOS_ROOT)/CocosDenshion/include \ - -I$(COCOS_ROOT)/scripting/lua/lua \ - -I$(COCOS_ROOT)/scripting/lua/tolua \ - -I$(COCOS_ROOT)/scripting/lua/cocos2dx_support \ - -I$(NACL_SDK_ROOT)/include \ - -I$(COCOS_ROOT)/external \ - -I$(COCOS_ROOT)/external/chipmunk/include/chipmunk \ - -I$(COCOS_ROOT)/extensions \ - -I$(COCOS_ROOT)/extensions/Components - -SOURCES = main.cpp \ - ../Classes/AppDelegate.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaEngine.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaStack.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaValue.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/Cocos2dxLuaLoader.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/LuaCocos2d.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/tolua_fix.c \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCBProxy.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/Lua_extensions_CCB.cpp - -include $(COCOS2DX_PATH)/../extensions/proj.nacl/Makefile -SOURCES += $(addprefix $(COCOS_ROOT)/extensions/, $(EXTENSIONS_SOURCES)) - -include $(COCOS_ROOT)/cocos2dx/proj.nacl/cocos2dx.mk - -CXXFLAGS += -Wno-multichar -STATICLIBS += -llua -lnosys -SHAREDLIBS += -lbox2d - -APP_NAME = HelloLua -TARGET = $(BIN_DIR)/$(APP_NAME)_$(NACL_ARCH).nexe -NMF = $(BIN_DIR)/$(APP_NAME).nmf - -all: $(NMF) - -$(TARGET): $(OBJECTS) $(LIB_DIR)/libcocos2d.a - @mkdir -p $(@D) - $(LOG_LINK)$(NACL_CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@ $(SHAREDLIBS) $(STATICLIBS) - -$(OBJ_DIR)/%.o: ../%.cpp - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: %.cpp - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: $(COCOS_ROOT)/%.cpp - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: $(COCOS_ROOT)/%.c - @mkdir -p $(@D) - $(LOG_CC)$(NACL_CC) -MMD $(CCFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(NMF): $(TARGET) - $(NACL_SDK_ROOT)/tools/create_nmf.py -o $@ $(BIN_DIR)/*.nexe $(NMF_FLAGS) -s $(BIN_DIR) - -run: all - /bin/cp -ar ../Resources/ . - $(NACL_SDK_ROOT)/tools/httpd.py --no_dir_check diff --git a/samples/Lua/HelloLua/proj.nacl/index.html b/samples/Lua/HelloLua/proj.nacl/index.html deleted file mode 100644 index cd401f1626..0000000000 --- a/samples/Lua/HelloLua/proj.nacl/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - cocos2dx HelloLua - - -

cocos2dx HelloLua

- - - -

-

- - diff --git a/samples/Lua/HelloLua/proj.nacl/main.cpp b/samples/Lua/HelloLua/proj.nacl/main.cpp deleted file mode 100644 index e4bce8fc75..0000000000 --- a/samples/Lua/HelloLua/proj.nacl/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "main.h" -#include "../Classes/AppDelegate.h" -#include "cocos2d.h" -#include "CCInstance.h" -#include "CCModule.h" - -#include -#include -#include -#include -#include - -#include "fcntl.h" -#include "sys/stat.h" - -USING_NS_CC; - -AppDelegate g_app; - -void* cocos_main(void* arg) -{ - fprintf(stderr, "in cocos_main\n"); - CocosPepperInstance* instance = (CocosPepperInstance*)arg; - alSetPpapiInfo(instance->pp_instance(), pp::Module::Get()->get_browser_interface()); - fprintf(stderr, "calling application->run\n"); - int rtn = Application::getInstance()->run(); - fprintf(stderr, "app run returned: %d\n", rtn); - return NULL; -} - -namespace pp -{ - -Module* CreateModule() -{ - return new CocosPepperModule(); -} - -} diff --git a/samples/Lua/HelloLua/proj.nacl/main.h b/samples/Lua/HelloLua/proj.nacl/main.h deleted file mode 100644 index 7ad9d5c9e4..0000000000 --- a/samples/Lua/HelloLua/proj.nacl/main.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __MAIN_H__ -#define __MAIN_H__ - -// C RunTime Header Files -#include "CCStdC.h" - -#endif // __MAIN_H__ diff --git a/samples/Lua/HelloLua/proj.tizen/.cproject b/samples/Lua/HelloLua/proj.tizen/.cproject deleted file mode 100644 index 082b16066d..0000000000 --- a/samples/Lua/HelloLua/proj.tizen/.cproject +++ /dev/null @@ -1,760 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Lua/HelloLua/proj.tizen/.project b/samples/Lua/HelloLua/proj.tizen/.project deleted file mode 100644 index 06b6c44cf6..0000000000 --- a/samples/Lua/HelloLua/proj.tizen/.project +++ /dev/null @@ -1,110 +0,0 @@ - - - proj.tizen - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - ?children? - ?name?=outputEntries\|?children?=?name?=entry\\\\\\\|\\\|?name?=entry\\\\\\\|\\\|?name?=entry\\\\\\\|\\\|\|| - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - sbi-make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/${ProjName}/Debug-Tizen-Emulator} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - true - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - org.tizen.nativecpp.apichecker.core.builder - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - org.tizen.nativecpp.apichecker.core.tizenCppNature - - - - src/Classes - 2 - PARENT-1-PROJECT_LOC/Classes - - - - - 1373007589779 - - 26 - - org.eclipse.ui.ide.multiFilter - 1.0-projectRelativePath-matches-false-false-*/.tpk - - - - diff --git a/samples/Lua/HelloLua/proj.tizen/data/.gitkeep b/samples/Lua/HelloLua/proj.tizen/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/HelloLua/proj.tizen/lib/.gitkeep b/samples/Lua/HelloLua/proj.tizen/lib/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/HelloLua/proj.tizen/manifest.xml b/samples/Lua/HelloLua/proj.tizen/manifest.xml deleted file mode 100644 index 2518a97d98..0000000000 --- a/samples/Lua/HelloLua/proj.tizen/manifest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - qc0zxC9NQi - 1.0.0 - C++App - - true - - - 2.2 - - - - - - HelloLua - - - mainmenu.png - - - - - diff --git a/samples/Lua/HelloLua/proj.tizen/res/.gitkeep b/samples/Lua/HelloLua/proj.tizen/res/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/HelloLua/proj.tizen/shared/data/.gitkeep b/samples/Lua/HelloLua/proj.tizen/shared/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/HelloLua/proj.tizen/shared/trusted/.gitkeep b/samples/Lua/HelloLua/proj.tizen/shared/trusted/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/HelloLua/proj.tizen/src/HelloLuaEntry.cpp b/samples/Lua/HelloLua/proj.tizen/src/HelloLuaEntry.cpp deleted file mode 100644 index 3ec1b2ae63..0000000000 --- a/samples/Lua/HelloLua/proj.tizen/src/HelloLuaEntry.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -Copyright (c) 2013 cocos2d-x.org -Copyright (c) 2013 Lee, Jae-Hong - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -// -// This file contains the Tizen application entry point. -// -#include "../../Classes/AppDelegate.h" -#include "cocos2d.h" - -USING_NS_CC; -using namespace Tizen::Base; -using namespace Tizen::Base::Collection; - -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus - -void -ApplicationInitialized(void) -{ - AppDelegate* pAppDelegate = new AppDelegate; - - auto eglView = EGLView::getInstance(); - eglView->setFrameSize(1280, 720); - - Application::getInstance()->run(); -} - -// -// The entry function of Tizen application called by the operating system. -// -_EXPORT_ int -OspMain(int argc, char *pArgv[]) -{ - AppLog("Application started."); - ArrayList args(SingleObjectDeleter); - args.Construct(); - for (int i = 0; i < argc; i++) - { - args.Add(new (std::nothrow) Tizen::Base::String(pArgv[i])); - } - - OspApplication::SetApplicationInitializedCallback(ApplicationInitialized); - OspApplication::SetScreenOrientation(Tizen::Ui::ORIENTATION_LANDSCAPE); - result r = Tizen::App::Application::Execute(OspApplication::CreateInstance, &args); - TryLog(r == E_SUCCESS, "[%s] Application execution failed", GetErrorMessage(r)); - AppLog("Application finished."); - - return static_cast(r); -} -#ifdef __cplusplus -} -#endif // __cplusplus diff --git a/samples/Lua/TestLua/proj.emscripten/Makefile b/samples/Lua/TestLua/proj.emscripten/Makefile deleted file mode 100644 index 89fbdf9a12..0000000000 --- a/samples/Lua/TestLua/proj.emscripten/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -EXECUTABLE = TestLua - -COCOS_ROOT = ../../../.. -INCLUDES = -I../ -I../Classes -I$(COCOS_ROOT)/CocosDenshion/include \ - -I$(COCOS_ROOT)/scripting/lua/lua \ - -I$(COCOS_ROOT)/scripting/lua/tolua \ - -I$(COCOS_ROOT)/scripting/lua/cocos2dx_support - -SOURCES = main.cpp ../Classes/AppDelegate.cpp - -SHAREDLIBS += -lcocos2d -lcocosdenshion -llua -COCOS_LIBS = $(LIB_DIR)/libcocos2d.so $(LIB_DIR)/libcocosdenshion.so $(LIB_DIR)/liblua.so - -include $(COCOS_ROOT)/cocos2dx/proj.emscripten/cocos2dx.mk - -$(TARGET): $(OBJECTS) $(STATICLIBS) $(COCOS_LIBS) $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - cp -a ../../../../samples/Cpp/TestCpp/Resources ../../../../samples/Lua/TestLua - cp -r ../../../../scripting/lua/script/ ../../../../samples/Lua/TestLua/Resources - $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@ $(SHAREDLIBS) $(STATICLIBS) $(LIBS) - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@ - -$(OBJ_DIR)/%.o: %.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@ diff --git a/samples/Lua/TestLua/proj.emscripten/main.cpp b/samples/Lua/TestLua/proj.emscripten/main.cpp deleted file mode 100644 index f114dbc8b7..0000000000 --- a/samples/Lua/TestLua/proj.emscripten/main.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "../Classes/AppDelegate.h" -#include "cocos2d.h" -#include "CCEGLView.h" - -#include -#include -#include -#include - -USING_NS_CC; - -int main(int argc, char **argv) -{ - // create the application instance - AppDelegate app; - auto eglView = EGLView::getInstance(); - eglView->setFrameSize(800, 480); - return Application::getInstance()->run(); -} diff --git a/samples/Lua/TestLua/proj.nacl/Makefile b/samples/Lua/TestLua/proj.nacl/Makefile deleted file mode 100644 index 2895ab652c..0000000000 --- a/samples/Lua/TestLua/proj.nacl/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -COCOS_ROOT = ../../../../ -COCOS2DX_PATH = $(COCOS_ROOT)/cocos2dx - -INCLUDES = -I.. \ - -I../Classes \ - -I$(COCOS_ROOT)/CocosDenshion/include \ - -I$(COCOS_ROOT)/scripting/lua/lua \ - -I$(COCOS_ROOT)/scripting/lua/tolua \ - -I$(COCOS_ROOT)/scripting/lua/cocos2dx_support \ - -I$(NACL_SDK_ROOT)/include \ - -I$(COCOS_ROOT)/external \ - -I$(COCOS_ROOT)/external/chipmunk/include/chipmunk \ - -I$(COCOS_ROOT)/extensions \ - -I$(COCOS_ROOT)/extensions/Components - -SOURCES = main.cpp \ - ../Classes/AppDelegate.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaEngine.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaStack.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCLuaValue.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/Cocos2dxLuaLoader.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/LuaCocos2d.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/tolua_fix.c \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/CCBProxy.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/Lua_extensions_CCB.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/LuaOpengl.cpp \ - $(COCOS_ROOT)/scripting/lua/cocos2dx_support/LuaScrollView.cpp - -include $(COCOS2DX_PATH)/../extensions/proj.nacl/Makefile -SOURCES += $(addprefix $(COCOS_ROOT)/extensions/, $(EXTENSIONS_SOURCES)) - -include $(COCOS_ROOT)/cocos2dx/proj.nacl/cocos2dx.mk - -CXXFLAGS += -Wno-multichar -STATICLIBS += -llua -SHAREDLIBS += -lbox2d - -APP_NAME = TestLua -TARGET = $(BIN_DIR)/$(APP_NAME)_$(NACL_ARCH).nexe -NMF = $(BIN_DIR)/$(APP_NAME).nmf - -all: $(NMF) - -$(TARGET): $(OBJECTS) $(LIB_DIR)/libcocos2d.a $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_LINK)$(NACL_CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@ $(SHAREDLIBS) $(STATICLIBS) - -$(OBJ_DIR)/%.o: %.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: $(COCOS_ROOT)/%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: $(COCOS_ROOT)/%.c $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CC)$(NACL_CC) -MMD $(CCFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(NMF): $(TARGET) - $(NACL_SDK_ROOT)/tools/create_nmf.py -o $@ $(BIN_DIR)/*.nexe $(NMF_FLAGS) -s $(BIN_DIR) - -run: all - /bin/cp -ar ../Resources/ . - $(NACL_SDK_ROOT)/tools/httpd.py --no_dir_check diff --git a/samples/Lua/TestLua/proj.nacl/index.html b/samples/Lua/TestLua/proj.nacl/index.html deleted file mode 100644 index 1c999373ca..0000000000 --- a/samples/Lua/TestLua/proj.nacl/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - cocos2dx TestLua - - -

cocos2dx TestLua

- - - -

-

- - diff --git a/samples/Lua/TestLua/proj.nacl/main.cpp b/samples/Lua/TestLua/proj.nacl/main.cpp deleted file mode 100644 index e8571e92c5..0000000000 --- a/samples/Lua/TestLua/proj.nacl/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "main.h" -#include "../Classes/AppDelegate.h" -#include "cocos2d.h" -#include "CCInstance.h" -#include "CCModule.h" - -#include -#include -#include -#include -#include - -USING_NS_CC; - -AppDelegate g_app; - -void* cocos_main(void* arg) -{ - fprintf(stderr, "in cocos_main\n"); - CocosPepperInstance* instance = (CocosPepperInstance*)arg; - alSetPpapiInfo(instance->pp_instance(), pp::Module::Get()->get_browser_interface()); - fprintf(stderr, "calling application->run\n"); - int rtn = Application::getInstance()->run(); - fprintf(stderr, "app run returned: %d\n", rtn); - return NULL; -} - -namespace pp -{ - -Module* CreateModule() -{ - return new CocosPepperModule(); -} - -} diff --git a/samples/Lua/TestLua/proj.nacl/main.h b/samples/Lua/TestLua/proj.nacl/main.h deleted file mode 100644 index 7ad9d5c9e4..0000000000 --- a/samples/Lua/TestLua/proj.nacl/main.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __MAIN_H__ -#define __MAIN_H__ - -// C RunTime Header Files -#include "CCStdC.h" - -#endif // __MAIN_H__ diff --git a/samples/Lua/TestLua/proj.tizen/.cproject b/samples/Lua/TestLua/proj.tizen/.cproject deleted file mode 100644 index 173493f4c3..0000000000 --- a/samples/Lua/TestLua/proj.tizen/.cproject +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Lua/TestLua/proj.tizen/.project b/samples/Lua/TestLua/proj.tizen/.project deleted file mode 100644 index 93037cf80e..0000000000 --- a/samples/Lua/TestLua/proj.tizen/.project +++ /dev/null @@ -1,106 +0,0 @@ - - - proj.tizen - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - sbi-make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/${ProjName}/Debug-Tizen-Emulator} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - true - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - org.tizen.nativecpp.apichecker.core.builder - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - org.tizen.nativecpp.apichecker.core.tizenCppNature - - - - src/Classes - 2 - PARENT-2-PROJECT_LOC/HelloLua/Classes - - - - - 1373009863403 - - 26 - - org.eclipse.ui.ide.multiFilter - 1.0-projectRelativePath-matches-false-false-*/.tpk - - - - diff --git a/samples/Lua/TestLua/proj.tizen/data/.gitkeep b/samples/Lua/TestLua/proj.tizen/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/inc/.gitkeep b/samples/Lua/TestLua/proj.tizen/inc/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/lib/.gitkeep b/samples/Lua/TestLua/proj.tizen/lib/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/manifest.xml b/samples/Lua/TestLua/proj.tizen/manifest.xml deleted file mode 100644 index 689fd8cfa4..0000000000 --- a/samples/Lua/TestLua/proj.tizen/manifest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - PHG8MiVSLl - 1.0.0 - C++App - - true - - - 2.2 - - - - - - TestLua - - - mainmenu.png - - - - - diff --git a/samples/Lua/TestLua/proj.tizen/res/.gitkeep b/samples/Lua/TestLua/proj.tizen/res/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/shared/data/.gitkeep b/samples/Lua/TestLua/proj.tizen/shared/data/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/shared/trusted/.gitkeep b/samples/Lua/TestLua/proj.tizen/shared/trusted/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/Lua/TestLua/proj.tizen/src/TestLuaEntry.cpp b/samples/Lua/TestLua/proj.tizen/src/TestLuaEntry.cpp deleted file mode 100644 index 3ec1b2ae63..0000000000 --- a/samples/Lua/TestLua/proj.tizen/src/TestLuaEntry.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -Copyright (c) 2013 cocos2d-x.org -Copyright (c) 2013 Lee, Jae-Hong - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -// -// This file contains the Tizen application entry point. -// -#include "../../Classes/AppDelegate.h" -#include "cocos2d.h" - -USING_NS_CC; -using namespace Tizen::Base; -using namespace Tizen::Base::Collection; - -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus - -void -ApplicationInitialized(void) -{ - AppDelegate* pAppDelegate = new AppDelegate; - - auto eglView = EGLView::getInstance(); - eglView->setFrameSize(1280, 720); - - Application::getInstance()->run(); -} - -// -// The entry function of Tizen application called by the operating system. -// -_EXPORT_ int -OspMain(int argc, char *pArgv[]) -{ - AppLog("Application started."); - ArrayList args(SingleObjectDeleter); - args.Construct(); - for (int i = 0; i < argc; i++) - { - args.Add(new (std::nothrow) Tizen::Base::String(pArgv[i])); - } - - OspApplication::SetApplicationInitializedCallback(ApplicationInitialized); - OspApplication::SetScreenOrientation(Tizen::Ui::ORIENTATION_LANDSCAPE); - result r = Tizen::App::Application::Execute(OspApplication::CreateInstance, &args); - TryLog(r == E_SUCCESS, "[%s] Application execution failed", GetErrorMessage(r)); - AppLog("Application finished."); - - return static_cast(r); -} -#ifdef __cplusplus -} -#endif // __cplusplus diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id deleted file mode 100644 index 131372c79f..0000000000 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -0243fae13fc45728b6dfe8d61ab64782e34c145f \ No newline at end of file diff --git a/scripting/auto-generated b/scripting/auto-generated deleted file mode 160000 index 6f5bc7bbd0..0000000000 --- a/scripting/auto-generated +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6f5bc7bbd036c76e7c6be121573662099997a0a4 diff --git a/scripting/javascript/bindings/js/debugger/DevToolsUtils.js b/scripting/javascript/bindings/js/debugger/DevToolsUtils.js deleted file mode 100644 index 26d0597644..0000000000 --- a/scripting/javascript/bindings/js/debugger/DevToolsUtils.js +++ /dev/null @@ -1,133 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -function utf16to8(str) { - var out, i, len, c; - - out = ""; - len = str.length; - for(i = 0; i < len; i++) - { - c = str.charCodeAt(i); - if ((c >= 0x0001) && (c <= 0x007F)) - { - out += str.charAt(i); - } - else if (c > 0x07FF) - { - out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); - out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); - out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); - } - else - { - out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); - out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); - } - } - return out; -} - -function utf8to16(str) { - var out, i, len, c; - var char2, char3; - - out = ""; - len = str.length; - i = 0; - while(i < len) { c = str.charCodeAt(i++); switch(c >> 4) - { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - // 0xxxxxxx - out += str.charAt(i-1); - break; - case 12: case 13: - // 110x xxxx 10xx xxxx - char2 = str.charCodeAt(i++); - out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - char2 = str.charCodeAt(i++); - char3 = str.charCodeAt(i++); - out += String.fromCharCode(((c & 0x0F) << 12) | - ((char2 & 0x3F) << 6) | - ((char3 & 0x3F) << 0)); - break; - } - } - - return out; - } - -var dump = function(msg) { - log(msg); -}; - -/* General utilities used throughout devtools. */ - -/* Turn the error e into a string, without fail. */ -this.safeErrorString = function safeErrorString(aError) { - try { - var s = aError.toString(); - if (typeof s === "string") - return s; - } catch (ee) { } - - return ""; -} - -/** - * Report that |aWho| threw an exception, |aException|. - */ -this.reportException = function reportException(aWho, aException) { - let msg = aWho + " threw an exception: " + safeErrorString(aException); - if (aException.stack) { - msg += "\nCall stack:\n" + aException.stack; - } - - dump(msg + "\n"); - - // if (Components.utils.reportError) { - // /* - // * Note that the xpcshell test harness registers an observer for - // * console messages, so when we're running tests, this will cause - // * the test to quit. - // */ - // Components.utils.reportError(msg); - // } -} - -/** - * Given a handler function that may throw, return an infallible handler - * function that calls the fallible handler, and logs any exceptions it - * throws. - * - * @param aHandler function - * A handler function, which may throw. - * @param aName string - * A name for aHandler, for use in error messages. If omitted, we use - * aHandler.name. - * - * (SpiderMonkey does generate good names for anonymous functions, but we - * don't have a way to get at them from JavaScript at the moment.) - */ -this.makeInfallible = function makeInfallible(aHandler, aName) { - if (!aName) - aName = aHandler.name; - - return function (/* arguments */) { - try { - return aHandler.apply(this, arguments); - } catch (ex) { - let who = "Handler function"; - if (aName) { - who += " " + aName; - } - reportException(who, ex); - } - } -} diff --git a/scripting/javascript/bindings/js/debugger/README.md b/scripting/javascript/bindings/js/debugger/README.md deleted file mode 100644 index 9e1d7bebd0..0000000000 --- a/scripting/javascript/bindings/js/debugger/README.md +++ /dev/null @@ -1,54 +0,0 @@ -Remote Debugging By Using FireFox -================================= - -Requirement ------------ - -* Firefox: From v24 - -How To Use ----------- - -### Prepare ### - -Please refer to https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging . - -### Enable Debugger Support For Your JSB Project ### - -``` -bool AppDelegate::applicationDidFinishLaunching() -{ - ... - - ScriptingCore* sc = ScriptingCore::getInstance(); - sc->addRegisterCallback(register_all_cocos2dx); - sc->addRegisterCallback(register_all_cocos2dx_extension); - sc->addRegisterCallback(register_cocos2dx_js_extensions); - sc->addRegisterCallback(jsb_register_chipmunk); - sc->addRegisterCallback(register_all_cocos2dx_extension_manual); - sc->addRegisterCallback(register_CCBuilderReader); - sc->addRegisterCallback(jsb_register_system); - sc->addRegisterCallback(JSB_register_opengl); - - sc->start(); - -#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) - sc->enableDebugger(); // Enable debugger here -#endif - - ... -} -``` - -Run your game. - -### Open Firefox And Follow The Step As Follows ### - - -![pic 1](https://lh5.googleusercontent.com/-HoxLGBdV2J0/UlZ7ZoFUjyI/AAAAAAAAADM/68GDaCQ1vP0/s0-I/Firefox-Remote-Debug01.jpg) -![pic 2](https://lh6.googleusercontent.com/-7FDIHAYsKAY/UlZ7Yf8W-pI/AAAAAAAAAFQ/joG0AymnuBk/s0-I/Firefox-Remote-Debug02.jpg) -![pic 3](https://lh4.googleusercontent.com/-idvnMRGcGy8/UlZ7Wj6DDuI/AAAAAAAAAC0/L9IVyHLNqeQ/s0-I/Firefox-Remote-Debug04.jpg) -![pic 4](https://lh6.googleusercontent.com/-YuZj7JGAtFE/UlZ9DDGDczI/AAAAAAAAAEQ/D2qIedjP5FU/s0-I/Firefox-Remote-Debug04.png.png) -![pic 5](https://lh3.googleusercontent.com/-cdIcNa3jT5c/UlZ9uapf3OI/AAAAAAAAAEg/MGq3vLHsauw/s0-I/Firefox-Remote-Debug05.png) -![pic 6](https://lh5.googleusercontent.com/-T79-o5ylJKI/UlZ_JJQe3MI/AAAAAAAAAE8/F63fSVxlJKs/s0-I/Firefox-Remote-Debug06.png) - diff --git a/scripting/javascript/bindings/js/debugger/actors/root.js b/scripting/javascript/bindings/js/debugger/actors/root.js deleted file mode 100644 index aa0d85342b..0000000000 --- a/scripting/javascript/bindings/js/debugger/actors/root.js +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* Root actor for the remote debugging protocol. */ - -/** - * Methods shared between RootActor and BrowserTabActor. - */ - -/** - * Populate |this._extraActors| as specified by |aFactories|, reusing whatever - * actors are already there. Add all actors in the final extra actors table to - * |aPool|. - * - * The root actor and the tab actor use this to instantiate actors that other - * parts of the browser have specified with DebuggerServer.addTabActor antd - * DebuggerServer.addGlobalActor. - * - * @param aFactories - * An object whose own property names are the names of properties to add to - * some reply packet (say, a tab actor grip or the "listTabs" response - * form), and whose own property values are actor constructor functions, as - * documented for addTabActor and addGlobalActor. - * - * @param this - * The BrowserRootActor or BrowserTabActor with which the new actors will - * be associated. It should support whatever API the |aFactories| - * constructor functions might be interested in, as it is passed to them. - * For the sake of CommonCreateExtraActors itself, it should have at least - * the following properties: - * - * - _extraActors - * An object whose own property names are factory table (and packet) - * property names, and whose values are no-argument actor constructors, - * of the sort that one can add to an ActorPool. - * - * - conn - * The DebuggerServerConnection in which the new actors will participate. - * - * - actorID - * The actor's name, for use as the new actors' parentID. - */ -function CommonCreateExtraActors(aFactories, aPool) { - // Walk over global actors added by extensions. - for (let name in aFactories) { - let actor = this._extraActors[name]; - if (!actor) { - actor = aFactories[name].bind(null, this.conn, this); - actor.prototype = aFactories[name].prototype; - actor.parentID = this.actorID; - this._extraActors[name] = actor; - } - aPool.addActor(actor); - } -} - -/** - * Append the extra actors in |this._extraActors|, constructed by a prior call - * to CommonCreateExtraActors, to |aObject|. - * - * @param aObject - * The object to which the extra actors should be added, under the - * property names given in the |aFactories| table passed to - * CommonCreateExtraActors. - * - * @param this - * The BrowserRootActor or BrowserTabActor whose |_extraActors| table we - * should use; see above. - */ -function CommonAppendExtraActors(aObject) { - for (let name in this._extraActors) { - let actor = this._extraActors[name]; - aObject[name] = actor.actorID; - } -} - -/** - * Create a remote debugging protocol root actor. - * - * @param aConnection - * The DebuggerServerConnection whose root actor we are constructing. - * - * @param aParameters - * The properties of |aParameters| provide backing objects for the root - * actor's requests; if a given property is omitted from |aParameters|, the - * root actor won't implement the corresponding requests or notifications. - * Supported properties: - * - * - tabList: a live list (see below) of tab actors. If present, the - * new root actor supports the 'listTabs' request, providing the live - * list's elements as its tab actors, and sending 'tabListChanged' - * notifications when the live list's contents change. One actor in - * this list must have a true '.selected' property. - * - * - globalActorFactories: an object |A| describing further actors to - * attach to the 'listTabs' reply. This is the type accumulated by - * DebuggerServer.addGlobalActor. For each own property |P| of |A|, - * the root actor adds a property named |P| to the 'listTabs' - * reply whose value is the name of an actor constructed by - * |A[P]|. - * - * - onShutdown: a function to call when the root actor is disconnected. - * - * Instance properties: - * - * - applicationType: the string the root actor will include as the - * "applicationType" property in the greeting packet. By default, this - * is "browser". - * - * Live lists: - * - * A "live list", as used for the |tabList|, is an object that presents a - * list of actors, and also notifies its clients of changes to the list. A - * live list's interface is two properties: - * - * - iterator: a method that returns an iterator. A for-of loop will call - * this method to obtain an iterator for the loop, so if LL is - * a live list, one can simply write 'for (i of LL) ...'. - * - * - onListChanged: a handler called, with no arguments, when the set of - * values the iterator would produce has changed since the last - * time 'iterator' was called. This may only be set to null or a - * callable value (one for which the typeof operator returns - * 'function'). (Note that the live list will not call the - * onListChanged handler until the list has been iterated over - * once; if nobody's seen the list in the first place, nobody - * should care if its contents have changed!) - * - * When the list changes, the list implementation should ensure that any - * actors yielded in previous iterations whose referents (tabs) still exist - * get yielded again in subsequent iterations. If the underlying referent - * is the same, the same actor should be presented for it. - * - * The root actor registers an 'onListChanged' handler on the appropriate - * list when it may need to send the client 'tabListChanged' notifications, - * and is careful to remove the handler whenever it does not need to send - * such notifications (including when it is disconnected). This means that - * live list implementations can use the state of the handler property (set - * or null) to install and remove observers and event listeners. - * - * Note that, as the only way for the root actor to see the members of the - * live list is to begin an iteration over the list, the live list need not - * actually produce any actors until they are reached in the course of - * iteration: alliterative lazy live lists. - */ -function RootActor(aConnection, aParameters) { - this.conn = aConnection; - this._parameters = aParameters; - this._onTabListChanged = this.onTabListChanged.bind(this); - this._extraActors = {}; -} - -RootActor.prototype = { - constructor: RootActor, - applicationType: "browser", - - /** - * Return a 'hello' packet as specified by the Remote Debugging Protocol. - */ - sayHello: function() { - return { - from: "root", - applicationType: this.applicationType, - /* This is not in the spec, but it's used by tests. */ - testConnectionPrefix: this.conn.prefix, - traits: { - sources: true - } - }; - }, - - /** - * Disconnects the actor from the browser window. - */ - disconnect: function() { - /* Tell the live lists we aren't watching any more. */ - if (this._parameters.tabList) { - this._parameters.tabList.onListChanged = null; - } - if (typeof this._parameters.onShutdown === 'function') { - this._parameters.onShutdown(); - } - this._extraActors = null; - }, - - /* The 'listTabs' request and the 'tabListChanged' notification. */ - - /** - * Handles the listTabs request. The actors will survive until at least - * the next listTabs request. - */ - onListTabs: function() { - - let tabList = this._parameters.tabList; - if (!tabList) { - return { from: "root", error: "noTabs", - message: "This root actor has no browser tabs." }; - } - - /* - * Walk the tab list, accumulating the array of tab actors for the - * reply, and moving all the actors to a new ActorPool. We'll - * replace the old tab actor pool with the one we build here, thus - * retiring any actors that didn't get listed again, and preparing any - * new actors to receive packets. - */ - let newActorPool = new ActorPool(this.conn); - let tabActorList = []; - let selected; - for (let tabActor of tabList) { - if (tabActor.selected) { - selected = tabActorList.length; - } - tabActor.parentID = this.actorID; - newActorPool.addActor(tabActor); - tabActorList.push(tabActor); - } - - /* DebuggerServer.addGlobalActor support: create actors. */ - this._createExtraActors(this._parameters.globalActorFactories, newActorPool); - - /* - * Drop the old actorID -> actor map. Actors that still mattered were - * added to the new map; others will go away. - */ - if (this._tabActorPool) { - this.conn.removeActorPool(this._tabActorPool); - } - this._tabActorPool = newActorPool; - this.conn.addActorPool(this._tabActorPool); - - let reply = { - "from": "root", - "selected": selected || 0, - "tabs": [actor.grip() for (actor of tabActorList)] - }; - - /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */ - this._appendExtraActors(reply); - - /* - * Now that we're actually going to report the contents of tabList to - * the client, we're responsible for letting the client know if it - * changes. - */ - tabList.onListChanged = this._onTabListChanged; - - return reply; - }, - - onTabListChanged: function () { - this.conn.send({ from:"root", type:"tabListChanged" }); - /* It's a one-shot notification; no need to watch any more. */ - this._parameters.tabList.onListChanged = null; - }, - - /* This is not in the spec, but it's used by tests. */ - onEcho: (aRequest) => aRequest, - - /* Support for DebuggerServer.addGlobalActor. */ - _createExtraActors: CommonCreateExtraActors, - _appendExtraActors: CommonAppendExtraActors, - - /* ThreadActor hooks. */ - - /** - * Prepare to enter a nested event loop by disabling debuggee events. - */ - preNest: function() { - // Disable events in all open windows. - let e = windowMediator.getEnumerator(null); - while (e.hasMoreElements()) { - let win = e.getNext(); - let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.suppressEventHandling(true); - windowUtils.suspendTimeouts(); - } - }, - - /** - * Prepare to exit a nested event loop by enabling debuggee events. - */ - postNest: function(aNestData) { - // Enable events in all open windows. - let e = windowMediator.getEnumerator(null); - while (e.hasMoreElements()) { - let win = e.getNext(); - let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.resumeTimeouts(); - windowUtils.suppressEventHandling(false); - } - }, - - /* ChromeDebuggerActor hooks. */ - - /** - * Add the specified actor to the default actor pool connection, in order to - * keep it alive as long as the server is. This is used by breakpoints in the - * thread and chrome debugger actors. - * - * @param actor aActor - * The actor object. - */ - addToParentPool: function(aActor) { - this.conn.addActor(aActor); - }, - - /** - * Remove the specified actor from the default actor pool. - * - * @param BreakpointActor aActor - * The actor object. - */ - removeFromParentPool: function(aActor) { - this.conn.removeActor(aActor); - } -} - -RootActor.prototype.requestTypes = { - "listTabs": RootActor.prototype.onListTabs, - "echo": RootActor.prototype.onEcho -}; diff --git a/scripting/javascript/bindings/js/debugger/actors/script.js b/scripting/javascript/bindings/js/debugger/actors/script.js deleted file mode 100644 index 7ddade2b54..0000000000 --- a/scripting/javascript/bindings/js/debugger/actors/script.js +++ /dev/null @@ -1,2948 +0,0 @@ -/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; js-indent-level: 2; -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/** - * JSD2 actors. - */ -/** - * Creates a ThreadActor. - * - * ThreadActors manage a JSInspector object and manage execution/inspection - * of debuggees. - * - * @param aHooks object - * An object with preNest and postNest methods for calling when entering - * and exiting a nested event loop, addToParentPool and - * removeFromParentPool methods for handling the lifetime of actors that - * will outlive the thread, like breakpoints. - * @param aGlobal object [optional] - * An optional (for content debugging only) reference to the content - * window. - */ -function ThreadActor(aHooks, aGlobal) -{ - this._state = "detached"; - this._frameActors = []; - this._environmentActors = []; - this._hooks = aHooks; - this.global = aGlobal; - - this.findGlobals = this.globalManager.findGlobals.bind(this); - this.onNewGlobal = this.globalManager.onNewGlobal.bind(this); - this.onNewSource = this.onNewSource.bind(this); - - this._options = { - useSourceMaps: false - }; -} - -/** - * The breakpoint store must be shared across instances of ThreadActor so that - * page reloads don't blow away all of our breakpoints. - */ -ThreadActor._breakpointStore = {}; - -ThreadActor.prototype = { - actorPrefix: "context", - - get state() { return this._state; }, - get attached() this.state == "attached" || - this.state == "running" || - this.state == "paused", - - get _breakpointStore() { return ThreadActor._breakpointStore; }, - - get threadLifetimePool() { - if (!this._threadLifetimePool) { - this._threadLifetimePool = new ActorPool(this.conn); - this.conn.addActorPool(this._threadLifetimePool); - this._threadLifetimePool.objectActors = new WeakMap(); - } - return this._threadLifetimePool; - }, - - get sources() { - if (!this._sources) { - this._sources = new ThreadSources(this, this._options.useSourceMaps, - this._allowSource, this.onNewSource); - } - return this._sources; - }, - - clearDebuggees: function TA_clearDebuggees() { - if (this.dbg) { - this.dbg.removeAllDebuggees(); - } - this.conn.removeActorPool(this._threadLifetimePool || undefined); - this._threadLifetimePool = null; - this._sources = null; - }, - - /** - * Add a debuggee global to the Debugger object. - */ - addDebuggee: function TA_addDebuggee(aGlobal) { - try { - this.dbg.addDebuggee(aGlobal); - } catch (e) { - // Ignore attempts to add the debugger's compartment as a debuggee. - dumpn("Ignoring request to add the debugger's compartment as a debuggee"); - } - }, - - /** - * Initialize the Debugger. - */ - _initDebugger: function TA__initDebugger() { - this.dbg = new Debugger(); - this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this); - this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this); - this.dbg.onNewScript = this.onNewScript.bind(this); - this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this); - // Keep the debugger disabled until a client attaches. - this.dbg.enabled = this._state != "detached"; - }, - - /** - * Remove a debuggee global from the JSInspector. - */ - removeDebugee: function TA_removeDebuggee(aGlobal) { - try { - this.dbg.removeDebuggee(aGlobal); - } catch(ex) { - // XXX: This debuggee has code currently executing on the stack, - // we need to save this for later. - } - }, - - /** - * Add the provided window and all windows in its frame tree as debuggees. - */ - _addDebuggees: function TA__addDebuggees(aWindow) { - this.addDebuggee(aWindow); - let frames = aWindow.frames; - if (frames) { - for (let i = 0; i < frames.length; i++) { - this._addDebuggees(frames[i]); - } - } - }, - - /** - * An object that will be used by ThreadActors to tailor their behavior - * depending on the debugging context being required (chrome or content). - */ - globalManager: { - findGlobals: function TA_findGlobals() { - this._addDebuggees(this.global); - }, - - /** - * A function that the engine calls when a new global object has been - * created. - * - * @param aGlobal Debugger.Object - * The new global object that was created. - */ - onNewGlobal: function TA_onNewGlobal(aGlobal) { - // Content debugging only cares about new globals in the contant window, - // like iframe children. - if (aGlobal.hostAnnotations && - aGlobal.hostAnnotations.type == "document" && - aGlobal.hostAnnotations.element === this.global) { - this.addDebuggee(aGlobal); - // Notify the client. - this.conn.send({ - from: this.actorID, - type: "newGlobal", - // TODO: after bug 801084 lands see if we need to JSONify this. - hostAnnotations: aGlobal.hostAnnotations - }); - } - } - }, - - disconnect: function TA_disconnect() { - dumpn("in ThreadActor.prototype.disconnect"); - if (this._state == "paused") { - this.onResume(); - } - - this._state = "exited"; - - this.clearDebuggees(); - - if (!this.dbg) { - return; - } - this.dbg.enabled = false; - this.dbg = null; - }, - - /** - * Disconnect the debugger and put the actor in the exited state. - */ - exit: function TA_exit() { - this.disconnect(); - }, - - // Request handlers - onAttach: function TA_onAttach(aRequest) { - if (this.state === "exited") { - return { type: "exited" }; - } - - if (this.state !== "detached") { - return { error: "wrongState" }; - } - - this._state = "attached"; - - update(this._options, aRequest.options || {}); - - if (!this.dbg) { - this._initDebugger(); - } - this.findGlobals(); - this.dbg.enabled = true; - try { - // Put ourselves in the paused state. - let packet = this._paused(); - if (!packet) { - return { error: "notAttached" }; - } - packet.why = { type: "attached" }; - - this._restoreBreakpoints(); - - // Send the response to the attach request now (rather than - // returning it), because we're going to start a nested event loop - // here. - this.conn.send(packet); - - // Start a nested event loop. - this._nest(); - - // We already sent a response to this request, don't send one - // now. - return null; - } catch (e) { - reportError(e); - return { error: "notAttached", message: e.toString() }; - } - }, - - onDetach: function TA_onDetach(aRequest) { - this.disconnect(); - dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet"); - return { - type: "detached" - }; - }, - - onReconfigure: function TA_onReconfigure(aRequest) { - if (this.state == "exited") { - return { error: "wrongState" }; - } - - update(this._options, aRequest.options || {}); - // Clear existing sources, so they can be recreated on next access. - this._sources = null; - - return {}; - }, - - /** - * Pause the debuggee, by entering a nested event loop, and return a 'paused' - * packet to the client. - * - * @param Debugger.Frame aFrame - * The newest debuggee frame in the stack. - * @param object aReason - * An object with a 'type' property containing the reason for the pause. - * @param function onPacket - * Hook to modify the packet before it is sent. Feel free to return a - * promise. - */ - _pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason, - onPacket=function (k) k) { - try { - let packet = this._paused(aFrame); - if (!packet) { - return undefined; - } - packet.why = aReason; - resolve(onPacket(packet)).then(this.conn.send.bind(this.conn)); - return this._nest(); - } catch(e) { - let msg = "Got an exception during TA__pauseAndRespond: " + e + - ": " + e.stack; - // Cu.reportError(msg); - dumpn(msg); - return undefined; - } - }, - - /** - * Handle a protocol request to resume execution of the debuggee. - */ - onResume: function TA_onResume(aRequest) { - if (this._state !== "paused") { - return { - error: "wrongState", - message: "Can't resume when debuggee isn't paused. Current state is '" - + this._state + "'" - }; - } - - // In case of multiple nested event loops (due to multiple debuggers open in - // different tabs or multiple debugger clients connected to the same tab) - // only allow resumption in a LIFO order. - if (DebuggerServer.xpcInspector.eventLoopNestLevel() > 1) { - log("DebuggerServer.xpcInspector.eventLoopNestLevel: "+DebuggerServer.xpcInspector.eventLoopNestLevel()); - // let lastNestRequestor = DebuggerServer.xpcInspector.lastNestRequestor; - // if (lastNestRequestor.connection != this.conn) { - // return { error: "wrongOrder", - // message: "trying to resume in the wrong order.", - // lastPausedUrl: lastNestRequestor.url }; - // } - } - - if (aRequest && aRequest.forceCompletion) { - // TODO: remove this when Debugger.Frame.prototype.pop is implemented in - // bug 736733. - if (typeof this.frame.pop != "function") { - return { error: "notImplemented", - message: "forced completion is not yet implemented." }; - } - - this.dbg.getNewestFrame().pop(aRequest.completionValue); - let packet = this._resumed(); - DebuggerServer.xpcInspector.exitNestedEventLoop(); - return { type: "resumeLimit", frameFinished: aRequest.forceCompletion }; - } - - if (aRequest && aRequest.resumeLimit) { - log("resumeLimit..."); - // Bind these methods because some of the hooks are called with 'this' - // set to the current frame. - let pauseAndRespond = (aFrame, onPacket=function (k) k) => { - this._pauseAndRespond(aFrame, { type: "resumeLimit" }, onPacket); - }; - let createValueGrip = this.createValueGrip.bind(this); - - let startFrame = this.youngestFrame; - let startLine; - if (this.youngestFrame.script) { - let offset = this.youngestFrame.offset; - startLine = this.youngestFrame.script.getOffsetLine(offset); - } - - // Define the JS hook functions for stepping. - - let onEnterFrame = aFrame => { - if (this.sources.isBlackBoxed(aFrame.script.url)) { - return undefined; - } - return pauseAndRespond(aFrame); - }; - - let thread = this; - - let onPop = function TA_onPop(aCompletion) { - // onPop is called with 'this' set to the current frame. - if (thread.sources.isBlackBoxed(this.script.url)) { - return undefined; - } - - // Note that we're popping this frame; we need to watch for - // subsequent step events on its caller. - this.reportedPop = true; - - return pauseAndRespond(this, (aPacket) => { - aPacket.why.frameFinished = {}; - if (!aCompletion) { - aPacket.why.frameFinished.terminated = true; - } else if (aCompletion.hasOwnProperty("return")) { - aPacket.why.frameFinished.return = createValueGrip(aCompletion.return); - } else if (aCompletion.hasOwnProperty("yield")) { - aPacket.why.frameFinished.return = createValueGrip(aCompletion.yield); - } else { - aPacket.why.frameFinished.throw = createValueGrip(aCompletion.throw); - } - return aPacket; - }); - }; - - let onStep = function TA_onStep() { - // onStep is called with 'this' set to the current frame. - - if (thread.sources.isBlackBoxed(this.script.url)) { - return undefined; - } - - // If we've changed frame or line, then report that. - if (this !== startFrame || - (this.script && - this.script.getOffsetLine(this.offset) != startLine)) { - return pauseAndRespond(this); - } - - // Otherwise, let execution continue. - return undefined; - }; - - let steppingType = aRequest.resumeLimit.type; - if (["step", "next", "finish"].indexOf(steppingType) == -1) { - return { error: "badParameterType", - message: "Unknown resumeLimit type" }; - } - // Make sure there is still a frame on the stack if we are to continue - // stepping. - let stepFrame = this._getNextStepFrame(startFrame); - if (stepFrame) { - switch (steppingType) { - case "step": - log("--> step..."); - this.dbg.onEnterFrame = onEnterFrame; - // Fall through. - case "next": - log("--> next..."); - stepFrame.onStep = onStep; - stepFrame.onPop = onPop; - break; - case "finish": - log("--> finish..."); - stepFrame.onPop = onPop; - } - } - - } - - if (aRequest && aRequest.pauseOnExceptions) { - this.dbg.onExceptionUnwind = this.onExceptionUnwind.bind(this); - } - let packet = this._resumed(); - DebuggerServer.xpcInspector.exitNestedEventLoop(); - return packet; - }, - - /** - * Helper method that returns the next frame when stepping. - */ - _getNextStepFrame: function TA__getNextStepFrame(aFrame) { - let stepFrame = aFrame.reportedPop ? aFrame.older : aFrame; - if (!stepFrame || !stepFrame.script) { - stepFrame = null; - } - return stepFrame; - }, - - onClientEvaluate: function TA_onClientEvaluate(aRequest) { - if (this.state !== "paused") { - return { error: "wrongState", - message: "Debuggee must be paused to evaluate code." }; - }; - - let frame = this._requestFrame(aRequest.frame); - if (!frame) { - return { error: "unknownFrame", - message: "Evaluation frame not found" }; - } - - if (!frame.environment) { - return { error: "notDebuggee", - message: "cannot access the environment of this frame." }; - }; - - // We'll clobber the youngest frame if the eval causes a pause, so - // save our frame now to be restored after eval returns. - // XXX: or we could just start using dbg.getNewestFrame() now that it - // works as expected. - let youngest = this.youngestFrame; - - // Put ourselves back in the running state and inform the client. - let resumedPacket = this._resumed(); - this.conn.send(resumedPacket); - - // Run the expression. - // XXX: test syntax errors - let completion = frame.eval(aRequest.expression); - - // Put ourselves back in the pause state. - let packet = this._paused(youngest); - packet.why = { type: "clientEvaluated", - frameFinished: this.createProtocolCompletionValue(completion) }; - - // Return back to our previous pause's event loop. - return packet; - }, - - onFrames: function TA_onFrames(aRequest) { - if (this.state !== "paused") { - return { error: "wrongState", - message: "Stack frames are only available while the debuggee is paused."}; - } - - let start = aRequest.start ? aRequest.start : 0; - let count = aRequest.count; - - // Find the starting frame... - let frame = this.youngestFrame; - let i = 0; - while (frame && (i < start)) { - frame = frame.older; - i++; - } - - // Return request.count frames, or all remaining - // frames if count is not defined. - let frames = []; - let promises = []; - for (; frame && (!count || i < (start + count)); i++, frame=frame.older) { - let form = this._createFrameActor(frame).form(); - form.depth = i; - frames.push(form); - - let promise = this.sources.getOriginalLocation(form.where.url, - form.where.line) - .then(function (aOrigLocation) { - form.where = aOrigLocation; - }); - promises.push(promise); - } - - return all(promises).then(function () { - return { frames: frames }; - }); - }, - - onReleaseMany: function TA_onReleaseMany(aRequest) { - if (!aRequest.actors) { - return { error: "missingParameter", - message: "no actors were specified" }; - } - - let res; - for each (let actorID in aRequest.actors) { - let actor = this.threadLifetimePool.get(actorID); - if (!actor) { - if (!res) { - res = { error: "notReleasable", - message: "Only thread-lifetime actors can be released." }; - } - continue; - } - actor.onRelease(); - } - return res ? res : {}; - }, - - /** - * Handle a protocol request to set a breakpoint. - */ - onSetBreakpoint: function TA_onSetBreakpoint(aRequest) { - if (this.state !== "paused") { - return { error: "wrongState", - message: "Breakpoints can only be set while the debuggee is paused."}; - } - - // XXX: `originalColumn` is never used. See bug 827639. - let { url: originalSource, - line: originalLine, - column: originalColumn } = aRequest.location; - - let locationPromise = this.sources.getGeneratedLocation(originalSource, - originalLine) - return locationPromise.then((aLocation) => { - let line = aLocation.line; - if (this.dbg.findScripts({ url: aLocation.url }).length == 0 || - line < 0 || - line == null) { - return { error: "noScript" }; - } - - // Add the breakpoint to the store for later reuse, in case it belongs to a - // script that hasn't appeared yet. - if (!this._breakpointStore[aLocation.url]) { - this._breakpointStore[aLocation.url] = []; - } - let scriptBreakpoints = this._breakpointStore[aLocation.url]; - scriptBreakpoints[line] = { - url: aLocation.url, - line: line, - column: aLocation.column - }; - - let response = this._setBreakpoint(aLocation); - // If the original location of our generated location is different from - // the original location we attempted to set the breakpoint on, we will - // need to know so that we can set actualLocation on the response. - let originalLocation = this.sources.getOriginalLocation(aLocation.url, - aLocation.line); - - return all([response, originalLocation]) - .then(([aResponse, {url, line}]) => { - if (aResponse.actualLocation) { - let actualOrigLocation = this.sources.getOriginalLocation( - aResponse.actualLocation.url, aResponse.actualLocation.line); - return actualOrigLocation.then(function ({ url, line }) { - if (url !== originalSource || line !== originalLine) { - aResponse.actualLocation = { url: url, line: line }; - } - return aResponse; - }); - } - - if (url !== originalSource || line !== originalLine) { - aResponse.actualLocation = { url: url, line: line }; - } - - return aResponse; - }); - }); - }, - - /** - * Set a breakpoint using the jsdbg2 API. If the line on which the breakpoint - * is being set contains no code, then the breakpoint will slide down to the - * next line that has runnable code. In this case the server breakpoint cache - * will be updated, so callers that iterate over the breakpoint cache should - * take that into account. - * - * @param object aLocation - * The location of the breakpoint as specified in the protocol. - */ - _setBreakpoint: function TA__setBreakpoint(aLocation) { - let breakpoints = this._breakpointStore[aLocation.url]; - - // Get or create the breakpoint actor for the given location - let actor; - if (breakpoints[aLocation.line].actor) { - actor = breakpoints[aLocation.line].actor; - } else { - actor = breakpoints[aLocation.line].actor = new BreakpointActor(this, { - url: aLocation.url, - line: aLocation.line - }); - this._hooks.addToParentPool(actor); - } - - // Find all scripts matching the given location - let scripts = this.dbg.findScripts(aLocation); - if (scripts.length == 0) { - return { - error: "noScript", - actor: actor.actorID - }; - } - - /** - * For each script, if the given line has at least one entry point, set - * breakpoint on the bytecode offet for each of them. - */ - let found = false; - for (let script of scripts) { - let offsets = script.getLineOffsets(aLocation.line); - if (offsets.length > 0) { - for (let offset of offsets) { - script.setBreakpoint(offset, actor); - } - actor.addScript(script, this); - found = true; - } - } - if (found) { - return { - actor: actor.actorID - }; - } - - /** - * If we get here, no breakpoint was set. This is because the given line - * has no entry points, for example because it is empty. As a fallback - * strategy, we try to set the breakpoint on the smallest line greater - * than or equal to the given line that as at least one entry point. - */ - - // Find all innermost scripts matching the given location - let scripts = this.dbg.findScripts({ - url: aLocation.url, - line: aLocation.line, - innermost: true - }); - - /** - * For each innermost script, look for the smallest line greater than or - * equal to the given line that has one or more entry points. If found, set - * a breakpoint on the bytecode offset for each of its entry points. - */ - let actualLocation; - let found = false; - for (let script of scripts) { - let offsets = script.getAllOffsets(); - for (let line = aLocation.line; line < offsets.length; ++line) { - if (offsets[line]) { - for (let offset of offsets[line]) { - script.setBreakpoint(offset, actor); - } - actor.addScript(script, this); - if (!actualLocation) { - actualLocation = { - url: aLocation.url, - line: line, - column: 0 - }; - } - found = true; - break; - } - } - } - if (found) { - if (breakpoints[actualLocation.line] && - breakpoints[actualLocation.line].actor) { - /** - * We already have a breakpoint actor for the actual location, so - * actor we created earlier is now redundant. Delete it, update the - * breakpoint store, and return the actor for the actual location. - */ - actor.onDelete(); - delete breakpoints[aLocation.line]; - return { - actor: breakpoints[actualLocation.line].actor.actorID, - actualLocation: actualLocation - }; - } else { - /** - * We don't have a breakpoint actor for the actual location yet. - * Instead or creating a new actor, reuse the actor we created earlier, - * and update the breakpoint store. - */ - actor.location = actualLocation; - breakpoints[actualLocation.line] = breakpoints[aLocation.line]; - delete breakpoints[aLocation.line]; - // WARNING: This overwrites aLocation.line - breakpoints[actualLocation.line].line = actualLocation.line; - return { - actor: actor.actorID, - actualLocation: actualLocation - }; - } - } - - /** - * If we get here, no line matching the given line was found, so just - * epically. - */ - return { - error: "noCodeAtLineColumn", - actor: actor.actorID - }; - }, - - /** - * Get the script and source lists from the debugger. - * - * TODO bug 637572: we should be dealing with sources directly, not inferring - * them through scripts. - */ - _discoverSources: function TA__discoverSources() { - // Only get one script per url. - let scriptsByUrl = {}; - for (let s of this.dbg.findScripts()) { - scriptsByUrl[s.url] = s; - } - - return all([this.sources.sourcesForScript(scriptsByUrl[s]) - for (s of Object.keys(scriptsByUrl))]); - }, - - onSources: function TA_onSources(aRequest) { - return this._discoverSources().then(() => { - return { - sources: [s.form() for (s of this.sources.iter())] - }; - }); - }, - - /** - * Disassociate all breakpoint actors from their scripts and clear the - * breakpoint handlers. This method can be used when the thread actor intends - * to keep the breakpoint store, but needs to clear any actual breakpoints, - * e.g. due to a page navigation. This way the breakpoint actors' script - * caches won't hold on to the Debugger.Script objects leaking memory. - */ - disableAllBreakpoints: function () { - for (let url in this._breakpointStore) { - for (let line in this._breakpointStore[url]) { - let bp = this._breakpointStore[url][line]; - bp.actor.removeScripts(); - } - } - }, - - /** - * Handle a protocol request to pause the debuggee. - */ - onInterrupt: function TA_onInterrupt(aRequest) { - if (this.state == "exited") { - return { type: "exited" }; - } else if (this.state == "paused") { - // TODO: return the actual reason for the existing pause. - return { type: "paused", why: { type: "alreadyPaused" } }; - } else if (this.state != "running") { - return { error: "wrongState", - message: "Received interrupt request in " + this.state + - " state." }; - } - - try { - // Put ourselves in the paused state. - let packet = this._paused(); - if (!packet) { - return { error: "notInterrupted" }; - } - packet.why = { type: "interrupted" }; - - // Send the response to the interrupt request now (rather than - // returning it), because we're going to start a nested event loop - // here. - this.conn.send(packet); - - // Start a nested event loop. - this._nest(); - - // We already sent a response to this request, don't send one - // now. - return null; - } catch (e) { - reportError(e); - return { error: "notInterrupted", message: e.toString() }; - } - }, - - /** - * Return the Debug.Frame for a frame mentioned by the protocol. - */ - _requestFrame: function TA_requestFrame(aFrameID) { - if (!aFrameID) { - return this.youngestFrame; - } - - if (this._framePool.has(aFrameID)) { - return this._framePool.get(aFrameID).frame; - } - - return undefined; - }, - - _paused: function TA_paused(aFrame) { - // We don't handle nested pauses correctly. Don't try - if we're - // paused, just continue running whatever code triggered the pause. - // We don't want to actually have nested pauses (although we - // have nested event loops). If code runs in the debuggee during - // a pause, it should cause the actor to resume (dropping - // pause-lifetime actors etc) and then repause when complete. - - if (this.state === "paused") { - return undefined; - } - - // Clear stepping hooks. - this.dbg.onEnterFrame = undefined; - this.dbg.onExceptionUnwind = undefined; - if (aFrame) { - aFrame.onStep = undefined; - aFrame.onPop = undefined; - } - - this._state = "paused"; - - // Save the pause frame (if any) as the youngest frame for - // stack viewing. - this.youngestFrame = aFrame; - - // Create the actor pool that will hold the pause actor and its - // children. - dbg_assert(!this._pausePool); - this._pausePool = new ActorPool(this.conn); - this.conn.addActorPool(this._pausePool); - - // Give children of the pause pool a quick link back to the - // thread... - this._pausePool.threadActor = this; - - // Create the pause actor itself... - dbg_assert(!this._pauseActor); - this._pauseActor = new PauseActor(this._pausePool); - this._pausePool.addActor(this._pauseActor); - - // Update the list of frames. - let poppedFrames = this._updateFrames(); - - // Send off the paused packet and spin an event loop. - let packet = { from: this.actorID, - type: "paused", - actor: this._pauseActor.actorID }; - if (aFrame) { - packet.frame = this._createFrameActor(aFrame).form(); - } - - if (poppedFrames) { - packet.poppedFrames = poppedFrames; - } - - return packet; - }, - - _nest: function TA_nest() { - if (this._hooks.preNest) { - var nestData = this._hooks.preNest(); - } - - let requestor = Object.create(null); - requestor.url = this._hooks.url; - requestor.connection = this.conn; - DebuggerServer.xpcInspector.enterNestedEventLoop(requestor); - - dbg_assert(this.state === "running"); - - if (this._hooks.postNest) { - this._hooks.postNest(nestData) - } - - // "continue" resumption value. - return undefined; - }, - - _resumed: function TA_resumed() { - this._state = "running"; - - // Drop the actors in the pause actor pool. - this.conn.removeActorPool(this._pausePool); - - this._pausePool = null; - this._pauseActor = null; - this.youngestFrame = null; - - return { from: this.actorID, type: "resumed" }; - }, - - /** - * Expire frame actors for frames that have been popped. - * - * @returns A list of actor IDs whose frames have been popped. - */ - _updateFrames: function TA_updateFrames() { - let popped = []; - - // Create the actor pool that will hold the still-living frames. - let framePool = new ActorPool(this.conn); - let frameList = []; - - for each (let frameActor in this._frameActors) { - if (frameActor.frame.live) { - framePool.addActor(frameActor); - frameList.push(frameActor); - } else { - popped.push(frameActor.actorID); - } - } - - // Remove the old frame actor pool, this will expire - // any actors that weren't added to the new pool. - if (this._framePool) { - this.conn.removeActorPool(this._framePool); - } - - this._frameActors = frameList; - this._framePool = framePool; - this.conn.addActorPool(framePool); - - return popped; - }, - - _createFrameActor: function TA_createFrameActor(aFrame) { - if (aFrame.actor) { - return aFrame.actor; - } - - let actor = new FrameActor(aFrame, this); - this._frameActors.push(actor); - this._framePool.addActor(actor); - aFrame.actor = actor; - - return actor; - }, - - /** - * Create and return an environment actor that corresponds to the provided - * Debugger.Environment. - * @param Debugger.Environment aEnvironment - * The lexical environment we want to extract. - * @param object aPool - * The pool where the newly-created actor will be placed. - * @return The EnvironmentActor for aEnvironment or undefined for host - * functions or functions scoped to a non-debuggee global. - */ - createEnvironmentActor: - function TA_createEnvironmentActor(aEnvironment, aPool) { - if (!aEnvironment) { - return undefined; - } - - if (aEnvironment.actor) { - return aEnvironment.actor; - } - - let actor = new EnvironmentActor(aEnvironment, this); - this._environmentActors.push(actor); - aPool.addActor(actor); - aEnvironment.actor = actor; - - return actor; - }, - - /** - * Create a grip for the given debuggee value. If the value is an - * object, will create an actor with the given lifetime. - */ - createValueGrip: function TA_createValueGrip(aValue, aPool=false) { - if (!aPool) { - aPool = this._pausePool; - } - let type = typeof(aValue); - - if (type === "string" && this._stringIsLong(aValue)) { - return this.longStringGrip(aValue, aPool); - } - - if (type === "boolean" || type === "string" || type === "number") { - return aValue; - } - - if (aValue === null) { - return { type: "null" }; - } - - if (aValue === undefined) { - return { type: "undefined" } - } - - if (typeof(aValue) === "object") { - return this.objectGrip(aValue, aPool); - } - - dbg_assert(false, "Failed to provide a grip for: " + aValue); - return null; - }, - - /** - * Return a protocol completion value representing the given - * Debugger-provided completion value. - */ - createProtocolCompletionValue: - function TA_createProtocolCompletionValue(aCompletion) { - let protoValue = {}; - if ("return" in aCompletion) { - protoValue.return = this.createValueGrip(aCompletion.return); - } else if ("yield" in aCompletion) { - protoValue.return = this.createValueGrip(aCompletion.yield); - } else if ("throw" in aCompletion) { - protoValue.throw = this.createValueGrip(aCompletion.throw); - } else { - protoValue.terminated = true; - } - return protoValue; - }, - - /** - * Create a grip for the given debuggee object. - * - * @param aValue Debugger.Object - * The debuggee object value. - * @param aPool ActorPool - * The actor pool where the new object actor will be added. - */ - objectGrip: function TA_objectGrip(aValue, aPool) { - if (!aPool.objectActors) { - aPool.objectActors = new WeakMap(); - } - - if (aPool.objectActors.has(aValue)) { - return aPool.objectActors.get(aValue).grip(); - } else if (this.threadLifetimePool.objectActors.has(aValue)) { - return this.threadLifetimePool.objectActors.get(aValue).grip(); - } - - let actor = new PauseScopedObjectActor(aValue, this); - aPool.addActor(actor); - aPool.objectActors.set(aValue, actor); - return actor.grip(); - }, - - /** - * Create a grip for the given debuggee object with a pause lifetime. - * - * @param aValue Debugger.Object - * The debuggee object value. - */ - pauseObjectGrip: function TA_pauseObjectGrip(aValue) { - if (!this._pausePool) { - throw "Object grip requested while not paused."; - } - - return this.objectGrip(aValue, this._pausePool); - }, - - /** - * Extend the lifetime of the provided object actor to thread lifetime. - * - * @param aActor object - * The object actor. - */ - threadObjectGrip: function TA_threadObjectGrip(aActor) { - // We want to reuse the existing actor ID, so we just remove it from the - // current pool's weak map and then let pool.addActor do the rest. - aActor.registeredPool.objectActors.delete(aActor.obj); - this.threadLifetimePool.addActor(aActor); - this.threadLifetimePool.objectActors.set(aActor.obj, aActor); - }, - - /** - * Handle a protocol request to promote multiple pause-lifetime grips to - * thread-lifetime grips. - * - * @param aRequest object - * The protocol request object. - */ - onThreadGrips: function OA_onThreadGrips(aRequest) { - if (this.state != "paused") { - return { error: "wrongState" }; - } - - if (!aRequest.actors) { - return { error: "missingParameter", - message: "no actors were specified" }; - } - - for (let actorID of aRequest.actors) { - let actor = this._pausePool.get(actorID); - if (actor) { - this.threadObjectGrip(actor); - } - } - return {}; - }, - - /** - * Create a grip for the given string. - * - * @param aString String - * The string we are creating a grip for. - * @param aPool ActorPool - * The actor pool where the new actor will be added. - */ - longStringGrip: function TA_longStringGrip(aString, aPool) { - if (!aPool.longStringActors) { - aPool.longStringActors = {}; - } - - if (aPool.longStringActors.hasOwnProperty(aString)) { - return aPool.longStringActors[aString].grip(); - } - - let actor = new LongStringActor(aString, this); - aPool.addActor(actor); - aPool.longStringActors[aString] = actor; - return actor.grip(); - }, - - /** - * Create a long string grip that is scoped to a pause. - * - * @param aString String - * The string we are creating a grip for. - */ - pauseLongStringGrip: function TA_pauseLongStringGrip (aString) { - return this.longStringGrip(aString, this._pausePool); - }, - - /** - * Create a long string grip that is scoped to a thread. - * - * @param aString String - * The string we are creating a grip for. - */ - threadLongStringGrip: function TA_pauseLongStringGrip (aString) { - return this.longStringGrip(aString, this._threadLifetimePool); - }, - - /** - * Returns true if the string is long enough to use a LongStringActor instead - * of passing the value directly over the protocol. - * - * @param aString String - * The string we are checking the length of. - */ - _stringIsLong: function TA__stringIsLong(aString) { - return aString.length >= DebuggerServer.LONG_STRING_LENGTH; - }, - - // JS Debugger API hooks. - - /** - * A function that the engine calls when a call to a debug event hook, - * breakpoint handler, watchpoint handler, or similar function throws some - * exception. - * - * @param aException exception - * The exception that was thrown in the debugger code. - */ - uncaughtExceptionHook: function TA_uncaughtExceptionHook(aException) { - dumpn("Got an exception: " + aException.message + "\n" + aException.stack); - }, - - /** - * A function that the engine calls when a debugger statement has been - * executed in the specified frame. - * - * @param aFrame Debugger.Frame - * The stack frame that contained the debugger statement. - */ - onDebuggerStatement: function TA_onDebuggerStatement(aFrame) { - if (this.sources.isBlackBoxed(aFrame.script.url)) { - return undefined; - } - return this._pauseAndRespond(aFrame, { type: "debuggerStatement" }); - }, - - /** - * A function that the engine calls when an exception has been thrown and has - * propagated to the specified frame. - * - * @param aFrame Debugger.Frame - * The youngest remaining stack frame. - * @param aValue object - * The exception that was thrown. - */ - onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) { - if (this.sources.isBlackBoxed(aFrame.script.url)) { - return undefined; - } - try { - let packet = this._paused(aFrame); - if (!packet) { - return undefined; - } - - packet.why = { type: "exception", - exception: this.createValueGrip(aValue) }; - this.conn.send(packet); - return this._nest(); - } catch(e) { - log("Got an exception during TA_onExceptionUnwind: " + e + - ": " + e.stack); - return undefined; - } - }, - - /** - * A function that the engine calls when a new script has been loaded into the - * scope of the specified debuggee global. - * - * @param aScript Debugger.Script - * The source script that has been loaded into a debuggee compartment. - * @param aGlobal Debugger.Object - * A Debugger.Object instance whose referent is the global object. - */ - onNewScript: function TA_onNewScript(aScript, aGlobal) { - this._addScript(aScript); - this.sources.sourcesForScript(aScript); - }, - - onNewSource: function TA_onNewSource(aSource) { - this.conn.send({ - from: this.actorID, - type: "newSource", - source: aSource.form() - }); - }, - - /** - * Check if scripts from the provided source URL are allowed to be stored in - * the cache. - * - * @param aSourceUrl String - * The url of the script's source that will be stored. - * @returns true, if the script can be added, false otherwise. - */ - _allowSource: function TA__allowSource(aSourceUrl) { - // Ignore anything we don't have a URL for (eval scripts, for example). - if (!aSourceUrl) - return false; - // Ignore XBL bindings for content debugging. - if (aSourceUrl.indexOf("chrome://") == 0) { - return false; - } - // Ignore about:* pages for content debugging. - if (aSourceUrl.indexOf("about:") == 0) { - return false; - } - return true; - }, - - /** - * Restore any pre-existing breakpoints to the scripts that we have access to. - */ - _restoreBreakpoints: function TA__restoreBreakpoints() { - for (let s of this.dbg.findScripts()) { - this._addScript(s); - } - }, - - /** - * Add the provided script to the server cache. - * - * @param aScript Debugger.Script - * The source script that will be stored. - * @returns true, if the script was added; false otherwise. - */ - _addScript: function TA__addScript(aScript) { - if (!this._allowSource(aScript.url)) { - return false; - } - - // Set any stored breakpoints. - let existing = this._breakpointStore[aScript.url]; - if (existing) { - let endLine = aScript.startLine + aScript.lineCount - 1; - // Iterate over the lines backwards, so that sliding breakpoints don't - // affect the loop. - for (let line = existing.length - 1; line >= aScript.startLine; line--) { - let bp = existing[line]; - // Only consider breakpoints that are not already associated with - // scripts, and limit search to the line numbers contained in the new - // script. - if (bp && !bp.actor.scripts.length && line <= endLine) { - this._setBreakpoint(bp); - } - } - } - return true; - }, - -}; - -ThreadActor.prototype.requestTypes = { - "attach": ThreadActor.prototype.onAttach, - "detach": ThreadActor.prototype.onDetach, - "reconfigure": ThreadActor.prototype.onReconfigure, - "resume": ThreadActor.prototype.onResume, - "clientEvaluate": ThreadActor.prototype.onClientEvaluate, - "frames": ThreadActor.prototype.onFrames, - "interrupt": ThreadActor.prototype.onInterrupt, - "releaseMany": ThreadActor.prototype.onReleaseMany, - "setBreakpoint": ThreadActor.prototype.onSetBreakpoint, - "sources": ThreadActor.prototype.onSources, - "threadGrips": ThreadActor.prototype.onThreadGrips -}; - - -/** - * Creates a PauseActor. - * - * PauseActors exist for the lifetime of a given debuggee pause. Used to - * scope pause-lifetime grips. - * - * @param ActorPool aPool - * The actor pool created for this pause. - */ -function PauseActor(aPool) -{ - this.pool = aPool; -} - -PauseActor.prototype = { - actorPrefix: "pause" -}; - - -/** - * A base actor for any actors that should only respond receive messages in the - * paused state. Subclasses may expose a `threadActor` which is used to help - * determine when we are in a paused state. Subclasses should set their own - * "constructor" property if they want better error messages. You should never - * instantiate a PauseScopedActor directly, only through subclasses. - */ -function PauseScopedActor() -{ -} - -/** - * A function decorator for creating methods to handle protocol messages that - * should only be received while in the paused state. - * - * @param aMethod Function - * The function we are decorating. - */ -PauseScopedActor.withPaused = function PSA_withPaused(aMethod) { - return function () { - if (this.isPaused()) { - return aMethod.apply(this, arguments); - } else { - return this._wrongState(); - } - }; -}; - -PauseScopedActor.prototype = { - - /** - * Returns true if we are in the paused state. - */ - isPaused: function PSA_isPaused() { - // When there is not a ThreadActor available (like in the webconsole) we - // have to be optimistic and assume that we are paused so that we can - // respond to requests. - return this.threadActor ? this.threadActor.state === "paused" : true; - }, - - /** - * Returns the wrongState response packet for this actor. - */ - _wrongState: function PSA_wrongState() { - return { - error: "wrongState", - message: this.constructor.name + - " actors can only be accessed while the thread is paused." - }; - } -}; - - -/** - * A SourceActor provides information about the source of a script. - * - * @param aUrl String - * The url of the source we are representing. - * @param aThreadActor ThreadActor - * The current thread actor. - * @param aSourceMap SourceMapConsumer - * Optional. The source map that introduced this source, if available. - */ -function SourceActor(aUrl, aThreadActor, aSourceMap=null) { - this._threadActor = aThreadActor; - this._url = aUrl; - this._sourceMap = aSourceMap; -} - -SourceActor.prototype = { - constructor: SourceActor, - actorPrefix: "source", - - get threadActor() this._threadActor, - get url() this._url, - - form: function SA_form() { - return { - actor: this.actorID, - url: this._url, - isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url) - // TODO bug 637572: introductionScript - }; - }, - - disconnect: function LSA_disconnect() { - if (this.registeredPool && this.registeredPool.sourceActors) { - delete this.registeredPool.sourceActors[this.actorID]; - } - }, - - /** - * Handler for the "source" packet. - */ - onSource: function SA_onSource(aRequest) { - let sourceContent = null; - if (this._sourceMap) { - sourceContent = this._sourceMap.sourceContentFor(this._url); - } - - if (sourceContent) { - return { - from: this.actorID, - source: this.threadActor.createValueGrip( - sourceContent, this.threadActor.threadLifetimePool) - }; - } - - // XXX bug 865252: Don't load from the cache if this is a source mapped - // source because we can't guarantee that the cache has the most up to date - // content for this source like we can if it isn't source mapped. - return fetch(this._url, { loadFromCache: !this._sourceMap }) - .then((aSource) => { - return this.threadActor.createValueGrip( - aSource, this.threadActor.threadLifetimePool); - }) - .then((aSourceGrip) => { - return { - from: this.actorID, - source: aSourceGrip - }; - }, (aError) => { - let msg = "Got an exception during SA_onSource: " + aError + - "\n" + aError.stack; - // Cu.reportError(msg); - dumpn(msg); - return { - "from": this.actorID, - "error": "loadSourceError", - "message": "Could not load the source for " + this._url + "." - }; - }); - }, - - /** - * Handler for the "blackbox" packet. - */ - onBlackBox: function SA_onBlackBox(aRequest) { - this.threadActor.sources.blackBox(this.url); - let packet = { - from: this.actorID - }; - if (this.threadActor.state == "paused" - && this.threadActor.youngestFrame - && this.threadActor.youngestFrame.script.url == this.url) { - packet.pausedInSource = true; - } - return packet; - }, - - /** - * Handler for the "unblackbox" packet. - */ - onUnblackBox: function SA_onUnblackBox(aRequest) { - this.threadActor.sources.unblackBox(this.url); - return { - from: this.actorID - }; - } -}; - -SourceActor.prototype.requestTypes = { - "source": SourceActor.prototype.onSource, - "blackbox": SourceActor.prototype.onBlackBox, - "unblackbox": SourceActor.prototype.onUnblackBox -}; - - -/** - * Creates an actor for the specified object. - * - * @param aObj Debugger.Object - * The debuggee object. - * @param aThreadActor ThreadActor - * The parent thread actor for this object. - */ -function ObjectActor(aObj, aThreadActor) -{ - this.obj = aObj; - this.threadActor = aThreadActor; -} - -ObjectActor.prototype = { - actorPrefix: "obj", - - /** - * Returns a grip for this actor for returning in a protocol message. - */ - grip: function OA_grip() { - let g = { - "type": "object", - "class": this.obj.class, - "actor": this.actorID, - "extensible": this.obj.isExtensible(), - "frozen": this.obj.isFrozen(), - "sealed": this.obj.isSealed() - }; - - // Add additional properties for functions. - if (this.obj.class === "Function") { - if (this.obj.name) { - g.name = this.obj.name; - } else if (this.obj.displayName) { - g.displayName = this.obj.displayName; - } - - // Check if the developer has added a de-facto standard displayName - // property for us to use. - let desc = this.obj.getOwnPropertyDescriptor("displayName"); - if (desc && desc.value && typeof desc.value == "string") { - g.userDisplayName = this.threadActor.createValueGrip(desc.value); - } - } - - return g; - }, - - /** - * Releases this actor from the pool. - */ - release: function OA_release() { - if (this.registeredPool.objectActors) { - this.registeredPool.objectActors.delete(this.obj); - } - this.registeredPool.removeActor(this); - }, - - /** - * Handle a protocol request to provide the names of the properties defined on - * the object and not its prototype. - * - * @param aRequest object - * The protocol request object. - */ - onOwnPropertyNames: function OA_onOwnPropertyNames(aRequest) { - return { from: this.actorID, - ownPropertyNames: this.obj.getOwnPropertyNames() }; - }, - - /** - * Handle a protocol request to provide the prototype and own properties of - * the object. - * - * @param aRequest object - * The protocol request object. - */ - onPrototypeAndProperties: function OA_onPrototypeAndProperties(aRequest) { - let ownProperties = Object.create(null); - let names; - try { - names = this.obj.getOwnPropertyNames(); - } catch (ex) { - // The above can throw if this.obj points to a dead object. - // TODO: we should use Cu.isDeadWrapper() - see bug 885800. - return { from: this.actorID, - prototype: this.threadActor.createValueGrip(null), - ownProperties: ownProperties, - safeGetterValues: Object.create(null) }; - } - for (let name of names) { - ownProperties[name] = this._propertyDescriptor(name); - } - return { from: this.actorID, - prototype: this.threadActor.createValueGrip(this.obj.proto), - ownProperties: ownProperties, - safeGetterValues: this._findSafeGetterValues(ownProperties) }; - }, - - /** - * Find the safe getter values for the current Debugger.Object, |this.obj|. - * - * @private - * @param object aOwnProperties - * The object that holds the list of known ownProperties for - * |this.obj|. - * @return object - * An object that maps property names to safe getter descriptors as - * defined by the remote debugging protocol. - */ - _findSafeGetterValues: function OA__findSafeGetterValues(aOwnProperties) - { - let safeGetterValues = Object.create(null); - let obj = this.obj; - let level = 0; - - while (obj) { - let getters = this._findSafeGetters(obj); - for (let name of getters) { - // Avoid overwriting properties from prototypes closer to this.obj. Also - // avoid providing safeGetterValues from prototypes if property |name| - // is already defined as an own property. - if (name in safeGetterValues || - (obj != this.obj && name in aOwnProperties)) { - continue; - } - - let desc = null, getter = null; - try { - desc = obj.getOwnPropertyDescriptor(name); - getter = desc.get; - } catch (ex) { - // The above can throw if the cache becomes stale. - } - if (!getter) { - obj._safeGetters = null; - continue; - } - - let result = getter.call(this.obj); - if (result && !("throw" in result)) { - let getterValue = undefined; - if ("return" in result) { - getterValue = result.return; - } else if ("yield" in result) { - getterValue = result.yield; - } - // WebIDL attributes specified with the LenientThis extended attribute - // return undefined and should be ignored. - if (getterValue !== undefined) { - safeGetterValues[name] = { - getterValue: this.threadActor.createValueGrip(getterValue), - getterPrototypeLevel: level, - enumerable: desc.enumerable, - writable: level == 0 ? desc.writable : true, - }; - } - } - } - - obj = obj.proto; - level++; - } - - return safeGetterValues; - }, - - /** - * Find the safe getters for a given Debugger.Object. Safe getters are native - * getters which are safe to execute. - * - * @private - * @param Debugger.Object aObject - * The Debugger.Object where you want to find safe getters. - * @return Set - * A Set of names of safe getters. This result is cached for each - * Debugger.Object. - */ - _findSafeGetters: function OA__findSafeGetters(aObject) - { - if (aObject._safeGetters) { - return aObject._safeGetters; - } - - let getters = new Set(); - for (let name of aObject.getOwnPropertyNames()) { - let desc = null; - try { - desc = aObject.getOwnPropertyDescriptor(name); - } catch (e) { - // Calling getOwnPropertyDescriptor on wrapped native prototypes is not - // allowed (bug 560072). - } - if (!desc || desc.value !== undefined || !("get" in desc)) { - continue; - } - - let fn = desc.get; - if (fn && fn.callable && fn.class == "Function" && - fn.script === undefined) { - getters.add(name); - } - } - - aObject._safeGetters = getters; - return getters; - }, - - /** - * Handle a protocol request to provide the prototype of the object. - * - * @param aRequest object - * The protocol request object. - */ - onPrototype: function OA_onPrototype(aRequest) { - return { from: this.actorID, - prototype: this.threadActor.createValueGrip(this.obj.proto) }; - }, - - /** - * Handle a protocol request to provide the property descriptor of the - * object's specified property. - * - * @param aRequest object - * The protocol request object. - */ - onProperty: function OA_onProperty(aRequest) { - if (!aRequest.name) { - return { error: "missingParameter", - message: "no property name was specified" }; - } - - return { from: this.actorID, - descriptor: this._propertyDescriptor(aRequest.name) }; - }, - - /** - * A helper method that creates a property descriptor for the provided object, - * properly formatted for sending in a protocol response. - * - * @param string aName - * The property that the descriptor is generated for. - */ - _propertyDescriptor: function OA_propertyDescriptor(aName) { - let desc; - try { - desc = this.obj.getOwnPropertyDescriptor(aName); - } catch (e) { - // Calling getOwnPropertyDescriptor on wrapped native prototypes is not - // allowed (bug 560072). Inform the user with a bogus, but hopefully - // explanatory, descriptor. - return { - configurable: false, - writable: false, - enumerable: false, - value: e.name - }; - } - - let retval = { - configurable: desc.configurable, - enumerable: desc.enumerable - }; - - if ("value" in desc) { - retval.writable = desc.writable; - retval.value = this.threadActor.createValueGrip(desc.value); - } else { - if ("get" in desc) { - retval.get = this.threadActor.createValueGrip(desc.get); - } - if ("set" in desc) { - retval.set = this.threadActor.createValueGrip(desc.set); - } - } - return retval; - }, - - /** - * Handle a protocol request to provide the source code of a function. - * - * @param aRequest object - * The protocol request object. - */ - onDecompile: function OA_onDecompile(aRequest) { - if (this.obj.class !== "Function") { - return { error: "objectNotFunction", - message: "decompile request is only valid for object grips " + - "with a 'Function' class." }; - } - - return { from: this.actorID, - decompiledCode: this.obj.decompile(!!aRequest.pretty) }; - }, - - /** - * Handle a protocol request to provide the parameters of a function. - * - * @param aRequest object - * The protocol request object. - */ - onParameterNames: function OA_onParameterNames(aRequest) { - if (this.obj.class !== "Function") { - return { error: "objectNotFunction", - message: "'parameterNames' request is only valid for object " + - "grips with a 'Function' class." }; - } - - return { parameterNames: this.obj.parameterNames }; - }, - - /** - * Handle a protocol request to release a thread-lifetime grip. - * - * @param aRequest object - * The protocol request object. - */ - onRelease: function OA_onRelease(aRequest) { - this.release(); - return {}; - }, -}; - -ObjectActor.prototype.requestTypes = { - "parameterNames": ObjectActor.prototype.onParameterNames, - "prototypeAndProperties": ObjectActor.prototype.onPrototypeAndProperties, - "prototype": ObjectActor.prototype.onPrototype, - "property": ObjectActor.prototype.onProperty, - "ownPropertyNames": ObjectActor.prototype.onOwnPropertyNames, - "decompile": ObjectActor.prototype.onDecompile, - "release": ObjectActor.prototype.onRelease, -}; - - -/** - * Creates a pause-scoped actor for the specified object. - * @see ObjectActor - */ -function PauseScopedObjectActor() -{ - ObjectActor.apply(this, arguments); -} - -PauseScopedObjectActor.prototype = Object.create(PauseScopedActor.prototype); - -update(PauseScopedObjectActor.prototype, ObjectActor.prototype); - -update(PauseScopedObjectActor.prototype, { - constructor: PauseScopedObjectActor, - - onOwnPropertyNames: - PauseScopedActor.withPaused(ObjectActor.prototype.onOwnPropertyNames), - - onPrototypeAndProperties: - PauseScopedActor.withPaused(ObjectActor.prototype.onPrototypeAndProperties), - - onPrototype: PauseScopedActor.withPaused(ObjectActor.prototype.onPrototype), - onProperty: PauseScopedActor.withPaused(ObjectActor.prototype.onProperty), - onDecompile: PauseScopedActor.withPaused(ObjectActor.prototype.onDecompile), - - onParameterNames: - PauseScopedActor.withPaused(ObjectActor.prototype.onParameterNames), - - /** - * Handle a protocol request to provide the lexical scope of a function. - * - * @param aRequest object - * The protocol request object. - */ - onScope: PauseScopedActor.withPaused(function OA_onScope(aRequest) { - if (this.obj.class !== "Function") { - return { error: "objectNotFunction", - message: "scope request is only valid for object grips with a" + - " 'Function' class." }; - } - - let envActor = this.threadActor.createEnvironmentActor(this.obj.environment, - this.registeredPool); - if (!envActor) { - return { error: "notDebuggee", - message: "cannot access the environment of this function." }; - } - - return { from: this.actorID, scope: envActor.form() }; - }), - - /** - * Handle a protocol request to promote a pause-lifetime grip to a - * thread-lifetime grip. - * - * @param aRequest object - * The protocol request object. - */ - onThreadGrip: PauseScopedActor.withPaused(function OA_onThreadGrip(aRequest) { - this.threadActor.threadObjectGrip(this); - return {}; - }), - - /** - * Handle a protocol request to release a thread-lifetime grip. - * - * @param aRequest object - * The protocol request object. - */ - onRelease: PauseScopedActor.withPaused(function OA_onRelease(aRequest) { - if (this.registeredPool !== this.threadActor.threadLifetimePool) { - return { error: "notReleasable", - message: "Only thread-lifetime actors can be released." }; - } - - this.release(); - return {}; - }), -}); - -update(PauseScopedObjectActor.prototype.requestTypes, { - "scope": PauseScopedObjectActor.prototype.onScope, - "threadGrip": PauseScopedObjectActor.prototype.onThreadGrip, -}); - - -/** - * Creates an actor for the specied "very long" string. "Very long" is specified - * at the server's discretion. - * - * @param aString String - * The string. - */ -function LongStringActor(aString) -{ - this.string = aString; - this.stringLength = aString.length; -} - -LongStringActor.prototype = { - - actorPrefix: "longString", - - disconnect: function LSA_disconnect() { - // Because longStringActors is not a weak map, we won't automatically leave - // it so we need to manually leave on disconnect so that we don't leak - // memory. - if (this.registeredPool && this.registeredPool.longStringActors) { - delete this.registeredPool.longStringActors[this.actorID]; - } - }, - - /** - * Returns a grip for this actor for returning in a protocol message. - */ - grip: function LSA_grip() { - return { - "type": "longString", - "initial": this.string.substring( - 0, DebuggerServer.LONG_STRING_INITIAL_LENGTH), - "length": this.stringLength, - "actor": this.actorID - }; - }, - - /** - * Handle a request to extract part of this actor's string. - * - * @param aRequest object - * The protocol request object. - */ - onSubstring: function LSA_onSubString(aRequest) { - return { - "from": this.actorID, - "substring": this.string.substring(aRequest.start, aRequest.end) - }; - }, - - /** - * Handle a request to release this LongStringActor instance. - */ - onRelease: function LSA_onRelease() { - // TODO: also check if registeredPool === threadActor.threadLifetimePool - // when the web console moves aray from manually releasing pause-scoped - // actors. - if (this.registeredPool.longStringActors) { - delete this.registeredPool.longStringActors[this.actorID]; - } - this.registeredPool.removeActor(this); - return {}; - }, -}; - -LongStringActor.prototype.requestTypes = { - "substring": LongStringActor.prototype.onSubstring, - "release": LongStringActor.prototype.onRelease -}; - - -/** - * Creates an actor for the specified stack frame. - * - * @param aFrame Debugger.Frame - * The debuggee frame. - * @param aThreadActor ThreadActor - * The parent thread actor for this frame. - */ -function FrameActor(aFrame, aThreadActor) -{ - this.frame = aFrame; - this.threadActor = aThreadActor; -} - -FrameActor.prototype = { - actorPrefix: "frame", - - /** - * A pool that contains frame-lifetime objects, like the environment. - */ - _frameLifetimePool: null, - get frameLifetimePool() { - if (!this._frameLifetimePool) { - this._frameLifetimePool = new ActorPool(this.conn); - this.conn.addActorPool(this._frameLifetimePool); - } - return this._frameLifetimePool; - }, - - /** - * Finalization handler that is called when the actor is being evicted from - * the pool. - */ - disconnect: function FA_disconnect() { - this.conn.removeActorPool(this._frameLifetimePool); - this._frameLifetimePool = null; - }, - - /** - * Returns a frame form for use in a protocol message. - */ - form: function FA_form() { - let form = { actor: this.actorID, - type: this.frame.type }; - if (this.frame.type === "call") { - form.callee = this.threadActor.createValueGrip(this.frame.callee); - } - - if (this.frame.environment) { - let envActor = this.threadActor - .createEnvironmentActor(this.frame.environment, - this.frameLifetimePool); - form.environment = envActor.form(); - } - form.this = this.threadActor.createValueGrip(this.frame.this); - form.arguments = this._args(); - if (this.frame.script) { - form.where = { url: this.frame.script.url, - line: this.frame.script.getOffsetLine(this.frame.offset) }; - form.isBlackBoxed = this.threadActor.sources.isBlackBoxed(this.frame.script.url) - } - - if (!this.frame.older) { - form.oldest = true; - } - - return form; - }, - - _args: function FA__args() { - if (!this.frame.arguments) { - return []; - } - - return [this.threadActor.createValueGrip(arg) - for each (arg in this.frame.arguments)]; - }, - - /** - * Handle a protocol request to pop this frame from the stack. - * - * @param aRequest object - * The protocol request object. - */ - onPop: function FA_onPop(aRequest) { - // TODO: remove this when Debugger.Frame.prototype.pop is implemented - if (typeof this.frame.pop != "function") { - return { error: "notImplemented", - message: "Popping frames is not yet implemented." }; - } - - while (this.frame != this.threadActor.dbg.getNewestFrame()) { - this.threadActor.dbg.getNewestFrame().pop(); - } - this.frame.pop(aRequest.completionValue); - - // TODO: return the watches property when frame pop watch actors are - // implemented. - return { from: this.actorID }; - } -}; - -FrameActor.prototype.requestTypes = { - "pop": FrameActor.prototype.onPop, -}; - - -/** - * Creates a BreakpointActor. BreakpointActors exist for the lifetime of their - * containing thread and are responsible for deleting breakpoints, handling - * breakpoint hits and associating breakpoints with scripts. - * - * @param ThreadActor aThreadActor - * The parent thread actor that contains this breakpoint. - * @param object aLocation - * The location of the breakpoint as specified in the protocol. - */ -function BreakpointActor(aThreadActor, aLocation) -{ - this.scripts = []; - this.threadActor = aThreadActor; - this.location = aLocation; -} - -BreakpointActor.prototype = { - actorPrefix: "breakpoint", - - /** - * Called when this same breakpoint is added to another Debugger.Script - * instance, in the case of a page reload. - * - * @param aScript Debugger.Script - * The new source script on which the breakpoint has been set. - * @param ThreadActor aThreadActor - * The parent thread actor that contains this breakpoint. - */ - addScript: function BA_addScript(aScript, aThreadActor) { - this.threadActor = aThreadActor; - this.scripts.push(aScript); - }, - - /** - * Remove the breakpoints from associated scripts and clear the script cache. - */ - removeScripts: function () { - for (let script of this.scripts) { - script.clearBreakpoint(this); - } - this.scripts = []; - }, - - /** - * A function that the engine calls when a breakpoint has been hit. - * - * @param aFrame Debugger.Frame - * The stack frame that contained the breakpoint. - */ - hit: function BA_hit(aFrame) { - if (this.threadActor.sources.isBlackBoxed(this.location.url)) { - return undefined; - } - - // TODO: add the rest of the breakpoints on that line (bug 676602). - let reason = { type: "breakpoint", actors: [ this.actorID ] }; - return this.threadActor._pauseAndRespond(aFrame, reason, (aPacket) => { - log("pause callback ..."); - - let { url, line } = aPacket.frame.where; - return this.threadActor.sources.getOriginalLocation(url, line) - .then(function (aOrigPosition) { - aPacket.frame.where = aOrigPosition; - return aPacket; - }); - }); - }, - - /** - * Handle a protocol request to remove this breakpoint. - * - * @param aRequest object - * The protocol request object. - */ - onDelete: function BA_onDelete(aRequest) { - // Remove from the breakpoint store. - let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url]; - delete scriptBreakpoints[this.location.line]; - this.threadActor._hooks.removeFromParentPool(this); - // Remove the actual breakpoint from the associated scripts. - this.removeScripts(); - - return { from: this.actorID }; - } -}; - -BreakpointActor.prototype.requestTypes = { - "delete": BreakpointActor.prototype.onDelete -}; - - -/** - * Creates an EnvironmentActor. EnvironmentActors are responsible for listing - * the bindings introduced by a lexical environment and assigning new values to - * those identifier bindings. - * - * @param Debugger.Environment aEnvironment - * The lexical environment that will be used to create the actor. - * @param ThreadActor aThreadActor - * The parent thread actor that contains this environment. - */ -function EnvironmentActor(aEnvironment, aThreadActor) -{ - this.obj = aEnvironment; - this.threadActor = aThreadActor; -} - -EnvironmentActor.prototype = { - actorPrefix: "environment", - - /** - * Return an environment form for use in a protocol message. - */ - form: function EA_form() { - let form = { actor: this.actorID }; - - // What is this environment's type? - if (this.obj.type == "declarative") { - form.type = this.obj.callee ? "function" : "block"; - } else { - form.type = this.obj.type; - } - - // Does this environment have a parent? - if (this.obj.parent) { - form.parent = (this.threadActor - .createEnvironmentActor(this.obj.parent, - this.registeredPool) - .form()); - } - - // Does this environment reflect the properties of an object as variables? - if (this.obj.type == "object" || this.obj.type == "with") { - form.object = this.threadActor.createValueGrip(this.obj.object); - } - - // Is this the environment created for a function call? - if (this.obj.callee) { - form.function = this.threadActor.createValueGrip(this.obj.callee); - } - - // Shall we list this environment's bindings? - if (this.obj.type == "declarative") { - form.bindings = this._bindings(); - } - - return form; - }, - - /** - * Return the identifier bindings object as required by the remote protocol - * specification. - */ - _bindings: function EA_bindings() { - let bindings = { arguments: [], variables: {} }; - - // TODO: this part should be removed in favor of the commented-out part - // below when getVariableDescriptor lands (bug 725815). - if (typeof this.obj.getVariable != "function") { - //if (typeof this.obj.getVariableDescriptor != "function") { - return bindings; - } - - let parameterNames; - if (this.obj.callee) { - parameterNames = this.obj.callee.parameterNames; - } - for each (let name in parameterNames) { - let arg = {}; - // TODO: this part should be removed in favor of the commented-out part - // below when getVariableDescriptor lands (bug 725815). - let desc = { - value: this.obj.getVariable(name), - configurable: false, - writable: true, - enumerable: true - }; - - // let desc = this.obj.getVariableDescriptor(name); - let descForm = { - enumerable: true, - configurable: desc.configurable - }; - if ("value" in desc) { - descForm.value = this.threadActor.createValueGrip(desc.value); - descForm.writable = desc.writable; - } else { - descForm.get = this.threadActor.createValueGrip(desc.get); - descForm.set = this.threadActor.createValueGrip(desc.set); - } - arg[name] = descForm; - bindings.arguments.push(arg); - } - - for each (let name in this.obj.names()) { - if (bindings.arguments.some(function exists(element) { - return !!element[name]; - })) { - continue; - } - - // TODO: this part should be removed in favor of the commented-out part - // below when getVariableDescriptor lands. - let desc = { - configurable: false, - writable: true, - enumerable: true - }; - try { - desc.value = this.obj.getVariable(name); - } catch (e) { - // Avoid "Debugger scope is not live" errors for |arguments|, introduced - // in bug 746601. - if (name != "arguments") { - throw e; - } - } - //let desc = this.obj.getVariableDescriptor(name); - let descForm = { - enumerable: true, - configurable: desc.configurable - }; - if ("value" in desc) { - descForm.value = this.threadActor.createValueGrip(desc.value); - descForm.writable = desc.writable; - } else { - descForm.get = this.threadActor.createValueGrip(desc.get); - descForm.set = this.threadActor.createValueGrip(desc.set); - } - bindings.variables[name] = descForm; - } - - return bindings; - }, - - /** - * Handle a protocol request to change the value of a variable bound in this - * lexical environment. - * - * @param aRequest object - * The protocol request object. - */ - onAssign: function EA_onAssign(aRequest) { - // TODO: enable the commented-out part when getVariableDescriptor lands - // (bug 725815). - /*let desc = this.obj.getVariableDescriptor(aRequest.name); - - if (!desc.writable) { - return { error: "immutableBinding", - message: "Changing the value of an immutable binding is not " + - "allowed" }; - }*/ - - try { - this.obj.setVariable(aRequest.name, aRequest.value); - } catch (e) { - if (e instanceof Debugger.DebuggeeWouldRun) { - return { error: "threadWouldRun", - cause: e.cause ? e.cause : "setter", - message: "Assigning a value would cause the debuggee to run" }; - } - // This should never happen, so let it complain loudly if it does. - throw e; - } - return { from: this.actorID }; - }, - - /** - * Handle a protocol request to fully enumerate the bindings introduced by the - * lexical environment. - * - * @param aRequest object - * The protocol request object. - */ - onBindings: function EA_onBindings(aRequest) { - return { from: this.actorID, - bindings: this._bindings() }; - } -}; - -EnvironmentActor.prototype.requestTypes = { - "assign": EnvironmentActor.prototype.onAssign, - "bindings": EnvironmentActor.prototype.onBindings -}; - -/** - * Override the toString method in order to get more meaningful script output - * for debugging the debugger. - */ -Debugger.Script.prototype.toString = function() { - let output = ""; - if (this.url) { - output += this.url; - } - if (typeof this.startLine != "undefined") { - output += ":" + this.startLine; - if (this.lineCount && this.lineCount > 1) { - output += "-" + (this.startLine + this.lineCount - 1); - } - } - if (this.strictMode) { - output += ":strict"; - } - return output; -}; - -/** - * Helper property for quickly getting to the line number a stack frame is - * currently paused at. - */ -Object.defineProperty(Debugger.Frame.prototype, "line", { - configurable: true, - get: function() { - if (this.script) { - return this.script.getOffsetLine(this.offset); - } else { - return null; - } - } -}); - - -/** - * Creates an actor for handling chrome debugging. ChromeDebuggerActor is a - * thin wrapper over ThreadActor, slightly changing some of its behavior. - * - * @param aConnection object - * The DebuggerServerConnection with which this ChromeDebuggerActor - * is associated. (Currently unused, but required to make this - * constructor usable with addGlobalActor.) - * - * @param aHooks object - * An object with preNest and postNest methods for calling when entering - * and exiting a nested event loop and also addToParentPool and - * removeFromParentPool methods for handling the lifetime of actors that - * will outlive the thread, like breakpoints. - */ -function ChromeDebuggerActor(aConnection, aHooks) -{ - ThreadActor.call(this, aHooks); -} - -ChromeDebuggerActor.prototype = Object.create(ThreadActor.prototype); - -update(ChromeDebuggerActor.prototype, { - constructor: ChromeDebuggerActor, - - // A constant prefix that will be used to form the actor ID by the server. - actorPrefix: "chromeDebugger", - - /** - * Override the eligibility check for scripts and sources to make sure every - * script and source with a URL is stored when debugging chrome. - */ - _allowSource: function(aSourceURL) !!aSourceURL, - - /** - * An object that will be used by ThreadActors to tailor their behavior - * depending on the debugging context being required (chrome or content). - * The methods that this object provides must be bound to the ThreadActor - * before use. - */ - globalManager: { - findGlobals: function CDA_findGlobals() { - // Add every global known to the debugger as debuggee. - this.dbg.addAllGlobalsAsDebuggees(); - }, - - /** - * A function that the engine calls when a new global object has been - * created. - * - * @param aGlobal Debugger.Object - * The new global object that was created. - */ - onNewGlobal: function CDA_onNewGlobal(aGlobal) { - this.addDebuggee(aGlobal); - // Notify the client. - this.conn.send({ - from: this.actorID, - type: "newGlobal", - // TODO: after bug 801084 lands see if we need to JSONify this. - hostAnnotations: aGlobal.hostAnnotations - }); - } - } -}); - - -/** - * Manages the sources for a thread. Handles source maps, locations in the - * sources, etc for ThreadActors. - */ -function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate, - aOnNewSource) { - this._thread = aThreadActor; - this._useSourceMaps = aUseSourceMaps; - this._allow = aAllowPredicate; - this._onNewSource = aOnNewSource; - - // source map URL --> promise of SourceMapConsumer - this._sourceMaps = Object.create(null); - // generated source url --> promise of SourceMapConsumer - this._sourceMapsByGeneratedSource = Object.create(null); - // original source url --> promise of SourceMapConsumer - this._sourceMapsByOriginalSource = Object.create(null); - // source url --> SourceActor - this._sourceActors = Object.create(null); - // original url --> generated url - this._generatedUrlsByOriginalUrl = Object.create(null); -} - -/** - * Must be a class property because it needs to persist across reloads, same as - * the breakpoint store. - */ -ThreadSources._blackBoxedSources = new Set(); - -ThreadSources.prototype = { - /** - * Return the source actor representing |aURL|, creating one if none - * exists already. Returns null if |aURL| is not allowed by the 'allow' - * predicate. - * - * Right now this takes a URL, but in the future it should - * take a Debugger.Source. See bug 637572. - * - * @param String aURL - * The source URL. - * @param optional SourceMapConsumer aSourceMap - * The source map that introduced this source, if any. - * @returns a SourceActor representing the source at aURL or null. - */ - source: function TS_source(aURL, aSourceMap=null) { - if (!this._allow(aURL)) { - return null; - } - - if (aURL in this._sourceActors) { - return this._sourceActors[aURL]; - } - - let actor = new SourceActor(aURL, this._thread, aSourceMap); - this._thread.threadLifetimePool.addActor(actor); - this._sourceActors[aURL] = actor; - try { - this._onNewSource(actor); - } catch (e) { - reportError(e); - } - return actor; - }, - - /** - * Return a promise of an array of source actors representing all the - * sources of |aScript|. - * - * If source map handling is enabled and |aScript| has a source map, then - * use it to find all of |aScript|'s *original* sources; return a promise - * of an array of source actors for those. - */ - sourcesForScript: function TS_sourcesForScript(aScript) { - if (!this._useSourceMaps || !aScript.sourceMapURL) { - return resolve([this.source(aScript.url)].filter(isNotNull)); - } - - return this.sourceMap(aScript) - .then((aSourceMap) => { - return [ - this.source(s, aSourceMap) for (s of aSourceMap.sources) - ]; - }) - .then(null, (e) => { - reportError(e); - delete this._sourceMaps[this._normalize(aScript.sourceMapURL, aScript.url)]; - delete this._sourceMapsByGeneratedSource[aScript.url]; - return [this.source(aScript.url)]; - }) - .then(function (aSources) { - return aSources.filter(isNotNull); - }); - }, - - /** - * Return a promise of a SourceMapConsumer for the source map for - * |aScript|; if we already have such a promise extant, return that. - * |aScript| must have a non-null sourceMapURL. - */ - sourceMap: function TS_sourceMap(aScript) { - if (aScript.url in this._sourceMapsByGeneratedSource) { - return this._sourceMapsByGeneratedSource[aScript.url]; - } - dbg_assert(aScript.sourceMapURL); - let sourceMapURL = this._normalize(aScript.sourceMapURL, aScript.url); - let map = this._fetchSourceMap(sourceMapURL) - .then((aSourceMap) => { - for (let s of aSourceMap.sources) { - this._generatedUrlsByOriginalUrl[s] = aScript.url; - this._sourceMapsByOriginalSource[s] = resolve(aSourceMap); - } - return aSourceMap; - }); - this._sourceMapsByGeneratedSource[aScript.url] = map; - return map; - }, - - /** - * Return a promise of a SourceMapConsumer for the source map located at - * |aAbsSourceMapURL|, which must be absolute. If there is already such a - * promise extant, return it. - */ - _fetchSourceMap: function TS__fetchSourceMap(aAbsSourceMapURL) { - if (aAbsSourceMapURL in this._sourceMaps) { - return this._sourceMaps[aAbsSourceMapURL]; - } else { - let promise = fetch(aAbsSourceMapURL).then((rawSourceMap) => { - let map = new SourceMapConsumer(rawSourceMap); - let base = aAbsSourceMapURL.replace(/\/[^\/]+$/, '/'); - if (base.indexOf("data:") !== 0) { - map.sourceRoot = map.sourceRoot - ? this._normalize(map.sourceRoot, base) - : base; - } - return map; - }); - this._sourceMaps[aAbsSourceMapURL] = promise; - return promise; - } - }, - - /** - * Returns a promise of the location in the original source if the source is - * source mapped, otherwise a promise of the same location. - * - * TODO bug 637572: take/return a column - */ - getOriginalLocation: function TS_getOriginalLocation(aSourceUrl, aLine) { - if (aSourceUrl in this._sourceMapsByGeneratedSource) { - return this._sourceMapsByGeneratedSource[aSourceUrl] - .then(function (aSourceMap) { - let { source, line } = aSourceMap.originalPositionFor({ - source: aSourceUrl, - line: aLine, - column: Infinity - }); - return { - url: source, - line: line - }; - }); - } - - // No source map - return resolve({ - url: aSourceUrl, - line: aLine - }); - }, - - /** - * Returns a promise of the location in the generated source corresponding to - * the original source and line given. - * - * When we pass a script S representing generated code to |sourceMap|, - * above, that returns a promise P. The process of resolving P populates - * the tables this function uses; thus, it won't know that S's original - * source URLs map to S until P is resolved. - * - * TODO bug 637572: take/return a column - */ - getGeneratedLocation: function TS_getGeneratedLocation(aSourceUrl, aLine) { - if (aSourceUrl in this._sourceMapsByOriginalSource) { - return this._sourceMapsByOriginalSource[aSourceUrl] - .then((aSourceMap) => { - let { line } = aSourceMap.generatedPositionFor({ - source: aSourceUrl, - line: aLine, - column: Infinity - }); - return { - url: this._generatedUrlsByOriginalUrl[aSourceUrl], - line: line - }; - }); - } - - // No source map - return resolve({ - url: aSourceUrl, - line: aLine - }); - }, - - /** - * Returns true if URL for the given source is black boxed. - * - * @param aURL String - * The URL of the source which we are checking whether it is black - * boxed or not. - */ - isBlackBoxed: function TS_isBlackBoxed(aURL) { - return ThreadSources._blackBoxedSources.has(aURL); - }, - - /** - * Add the given source URL to the set of sources that are black boxed. If the - * thread is currently paused and we are black boxing the yougest frame's - * source, this will force a step. - * - * @param aURL String - * The URL of the source which we are black boxing. - */ - blackBox: function TS_blackBox(aURL) { - ThreadSources._blackBoxedSources.add(aURL); - }, - - /** - * Remove the given source URL to the set of sources that are black boxed. - * - * @param aURL String - * The URL of the source which we are no longer black boxing. - */ - unblackBox: function TS_unblackBox(aURL) { - ThreadSources._blackBoxedSources.delete(aURL); - }, - - /** - * Normalize multiple relative paths towards the base paths on the right. - */ - _normalize: function TS__normalize(...aURLs) { - dbg_assert(aURLs.length > 1); - let base = Services.io.newURI(aURLs.pop(), null, null); - let url; - while ((url = aURLs.pop())) { - base = Services.io.newURI(url, null, base); - } - return base.spec; - }, - - iter: function TS_iter() { - for (let url in this._sourceActors) { - yield this._sourceActors[url]; - } - } -}; - -// Utility functions. - -/** - * Utility function for updating an object with the properties of another - * object. - * - * @param aTarget Object - * The object being updated. - * @param aNewAttrs Object - * The new attributes being set on the target. - */ -function update(aTarget, aNewAttrs) { - for (let key in aNewAttrs) { - let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key); - - if (desc) { - Object.defineProperty(aTarget, key, desc); - } - } -} - -/** - * Returns true if its argument is not null. - */ -function isNotNull(aThing) { - return aThing !== null; -} - -/** - * Performs a request to load the desired URL and returns a promise. - * - * @param aURL String - * The URL we will request. - * @returns Promise - * A promise of the document at that URL, as a string. - * - * XXX: It may be better to use nsITraceableChannel to get to the sources - * without relying on caching when we can (not for eval, etc.): - * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ - */ -function fetch(aURL, aOptions={ loadFromCache: true }) { - let deferred = defer(); - let scheme; - let url = aURL.split(" -> ").pop(); - let charset; - let filePath = url; - // try { - // scheme = Services.io.extractScheme(url); - // } catch (e) { - // In the xpcshell tests, the script url is the absolute path of the test - // file, which will make a malformed URI error be thrown. Add the file - // scheme prefix ourselves. - url = "file://" + url; - // scheme = Services.io.extractScheme(url); - // } - scheme = "file"; - - switch (scheme) { - case "file": - case "chrome": - case "resource": - try { - // NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) { - // if (!Components.isSuccessCode(aStatus)) { - // deferred.reject("Request failed: " + url); - // return; - // } - let cc = globalDebuggee.cc; - let fileUtils = cc.FileUtils.getInstance(); - let source = fileUtils.getStringFromFile(filePath);//NetUtil.readInputStreamToString(aStream, aStream.available()); - if (!source) - { - deferred.reject("Request failed: " + url); - } - else - { - deferred.resolve(source); - } - // aStream.close(); - // }); - } catch (ex) { - deferred.reject("Request failed: " + url); - } - break; - - default: - let channel; - try { - channel = Services.io.newChannel(url, null, null); - } catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") { - // On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but - // newChannel won't be able to handle it. - url = "file:///" + url; - channel = Services.io.newChannel(url, null, null); - } - let chunks = []; - let streamListener = { - onStartRequest: function(aRequest, aContext, aStatusCode) { - if (!Components.isSuccessCode(aStatusCode)) { - deferred.reject("Request failed: " + url); - } - }, - onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) { - chunks.push(NetUtil.readInputStreamToString(aStream, aCount)); - }, - onStopRequest: function(aRequest, aContext, aStatusCode) { - if (!Components.isSuccessCode(aStatusCode)) { - deferred.reject("Request failed: " + url); - return; - } - - charset = channel.contentCharset; - deferred.resolve(chunks.join("")); - } - }; - - channel.loadFlags = aOptions.loadFromCache - ? channel.LOAD_FROM_CACHE - : channel.LOAD_BYPASS_CACHE; - channel.asyncOpen(streamListener, null); - break; - } - - return deferred.promise.then(function (source) { - return convertToUnicode(source, charset); - }); -} - -/** - * Convert a given string, encoded in a given character set, to unicode. - * - * @param string aString - * A string. - * @param string aCharset - * A character set. - */ -function convertToUnicode(aString, aCharset=null) { - // Decoding primitives. - // let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - // .createInstance(Ci.nsIScriptableUnicodeConverter); - // try { - // converter.charset = aCharset || "UTF-8"; - // return converter.ConvertToUnicode(aString); - // } catch(e) { - return aString; - // } -} - -/** - * Report the given error in the error console and to stdout. - */ -function reportError(aError) { - // Cu.reportError(aError); - dumpn(aError.message + ":\n" + aError.stack); -} diff --git a/scripting/javascript/bindings/js/debugger/core/promise.js b/scripting/javascript/bindings/js/debugger/core/promise.js deleted file mode 100644 index a695f5a3ad..0000000000 --- a/scripting/javascript/bindings/js/debugger/core/promise.js +++ /dev/null @@ -1,294 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 expandtab */ -/*jshint undef: true es5: true node: true browser: true devel: true - forin: true latedef: false */ -/*global define: true, Cu: true, __URI__: true */ -//;(function(id, factory) { // Module boilerplate :( -// if (typeof(define) === 'function') { // RequireJS -// define(factory); -// } else if (typeof(require) === 'function') { // CommonJS -// factory.call(this, require, exports, module); -// } else if (String(this).indexOf('BackstagePass') >= 0) { // JSM -// this[factory.name] = {}; -// try { -// this.console = this['Components'].utils -// .import('resource://gre/modules/devtools/Console.jsm', {}).console; -// } -// catch (ex) { -// // Avoid failures on different toolkit configurations. -// } -// factory(function require(uri) { -// var imports = {}; -// this['Components'].utils.import(uri, imports); -// return imports; -// }, this[factory.name], { uri: __URI__, id: id }); -// this.EXPORTED_SYMBOLS = [factory.name]; -// } else { // Browser or alike -// var globals = this; -// factory(function require(id) { -// return globals[id]; -// }, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id }); -// } -//}).call(this, 'promise/core', function Promise(require, exports, module) { - -'use strict'; - -var exports = exports || {}; - -//module.metadata = { -// "stability": "unstable" -//}; - -/** - * Internal utility: Wraps given `value` into simplified promise, successfully - * fulfilled to a given `value`. Note the result is not a complete promise - * implementation, as its method `then` does not returns anything. - */ -function fulfilled(value) { - return { then: function then(fulfill) { fulfill(value); } }; -} - -/** - * Internal utility: Wraps given input into simplified promise, pre-rejected - * with a given `reason`. Note the result is not a complete promise - * implementation, as its method `then` does not returns anything. - */ -function rejected(reason) { - return { then: function then(fulfill, reject) { reject(reason); } }; -} - -/** - * Internal utility: Returns `true` if given `value` is a promise. Value is - * assumed to be a promise if it implements method `then`. - */ -function isPromise(value) { - return value && typeof(value.then) === 'function'; -} - -/** - * Creates deferred object containing fresh promise & methods to either resolve - * or reject it. The result is an object with the following properties: - * - `promise` Eventual value representation implementing CommonJS [Promises/A] - * (http://wiki.commonjs.org/wiki/Promises/A) API. - * - `resolve` Single shot function that resolves enclosed `promise` with a - * given `value`. - * - `reject` Single shot function that rejects enclosed `promise` with a given - * `reason`. - * - * An optional `prototype` argument is used as a prototype of the returned - * `promise` allowing one to implement additional API. If prototype is not - * passed then it falls back to `Object.prototype`. - * - * ## Example - * - * function fetchURI(uri, type) { - * var deferred = defer(); - * var request = new XMLHttpRequest(); - * request.open("GET", uri, true); - * request.responseType = type; - * request.onload = function onload() { - * deferred.resolve(request.response); - * } - * request.onerror = function(event) { - * deferred.reject(event); - * } - * request.send(); - * - * return deferred.promise; - * } - */ -function defer(prototype) { - // Define FIFO queue of observer pairs. Once promise is resolved & all queued - // observers are forwarded to `result` and variable is set to `null`. - var observers = []; - - // Promise `result`, which will be assigned a resolution value once promise - // is resolved. Note that result will always be assigned promise (or alike) - // object to take care of propagation through promise chains. If result is - // `null` promise is not resolved yet. - var result = null; - - prototype = (prototype || prototype === null) ? prototype : Object.prototype; - - // Create an object implementing promise API. - var promise = Object.create(prototype, { - then: { value: function then(onFulfill, onError) { - var deferred = defer(prototype); - - function resolve(value) { - // If `onFulfill` handler is provided resolve `deferred.promise` with - // result of invoking it with a resolution value. If handler is not - // provided propagate value through. - try { - deferred.resolve(onFulfill ? onFulfill(value) : value); - } - // `onFulfill` may throw exception in which case resulting promise - // is rejected with thrown exception. - catch(error) { - if (exports._reportErrors && typeof(console) === 'object') - console.error(error); - // Note: Following is equivalent of `deferred.reject(error)`, - // we use this shortcut to reduce a stack. - deferred.resolve(rejected(error)); - } - } - - function reject(reason) { - try { - if (onError) deferred.resolve(onError(reason)); - else deferred.resolve(rejected(reason)); - } - catch(error) { - if (exports._reportErrors && typeof(console) === 'object') - console.error(error); - deferred.resolve(rejected(error)); - } - } - - // If enclosed promise (`this.promise`) observers queue is still alive - // enqueue a new observer pair into it. Note that this does not - // necessary means that promise is pending, it may already be resolved, - // but we still have to queue observers to guarantee an order of - // propagation. - if (observers) { - observers.push({ resolve: resolve, reject: reject }); - } - // Otherwise just forward observer pair right to a `result` promise. - else { - result.then(resolve, reject); - } - - return deferred.promise; - }} - }) - - var deferred = { - promise: promise, - /** - * Resolves associated `promise` to a given `value`, unless it's already - * resolved or rejected. Note that resolved promise is not necessary a - * successfully fulfilled. Promise may be resolved with a promise `value` - * in which case `value` promise's fulfillment / rejection will propagate - * up to a promise resolved with `value`. - */ - resolve: function resolve(value) { - if (!result) { - // Store resolution `value` in a `result` as a promise, so that all - // the subsequent handlers can be simply forwarded to it. Since - // `result` will be a promise all the value / error propagation will - // be uniformly taken care of. - result = isPromise(value) ? value : fulfilled(value); - - // Forward already registered observers to a `result` promise in the - // order they were registered. Note that we intentionally dequeue - // observer at a time until queue is exhausted. This makes sure that - // handlers registered as side effect of observer forwarding are - // queued instead of being invoked immediately, guaranteeing FIFO - // order. - while (observers.length) { - var observer = observers.shift(); - result.then(observer.resolve, observer.reject); - } - - // Once `observers` queue is exhausted we `null`-ify it, so that - // new handlers are forwarded straight to the `result`. - observers = null; - } - }, - /** - * Rejects associated `promise` with a given `reason`, unless it's already - * resolved / rejected. This is just a (better performing) convenience - * shortcut for `deferred.resolve(reject(reason))`. - */ - reject: function reject(reason) { - // Note that if promise is resolved that does not necessary means that it - // is successfully fulfilled. Resolution value may be a promise in which - // case its result propagates. In other words if promise `a` is resolved - // with promise `b`, `a` is either fulfilled or rejected depending - // on weather `b` is fulfilled or rejected. Here `deferred.promise` is - // resolved with a promise pre-rejected with a given `reason`, there for - // `deferred.promise` is rejected with a given `reason`. This may feel - // little awkward first, but doing it this way greatly simplifies - // propagation through promise chains. - deferred.resolve(rejected(reason)); - } - }; - - return deferred; -} -exports.defer = defer; - -/** - * Returns a promise resolved to a given `value`. Optionally a second - * `prototype` argument may be provided to be used as a prototype for the - * returned promise. - */ -function resolve(value, prototype) { - var deferred = defer(prototype); - deferred.resolve(value); - return deferred.promise; -} -exports.resolve = resolve; - -/** - * Returns a promise rejected with a given `reason`. Optionally a second - * `prototype` argument may be provided to be used as a prototype for the - * returned promise. - */ -function reject(reason, prototype) { - var deferred = defer(prototype); - deferred.reject(reason); - return deferred.promise; -} -exports.reject = reject; - -var promised = (function() { - // Note: Define shortcuts and utility functions here in order to avoid - // slower property accesses and unnecessary closure creations on each - // call of this popular function. - - var call = Function.call; - var concat = Array.prototype.concat; - - // Utility function that does following: - // execute([ f, self, args...]) => f.apply(self, args) - function execute(args) { return call.apply(call, args) } - - // Utility function that takes promise of `a` array and maybe promise `b` - // as arguments and returns promise for `a.concat(b)`. - function promisedConcat(promises, unknown) { - return promises.then(function(values) { - return resolve(unknown).then(function(value) { - return values.concat([ value ]); - }); - }); - } - - return function promised(f, prototype) { - /** - Returns a wrapped `f`, which when called returns a promise that resolves to - `f(...)` passing all the given arguments to it, which by the way may be - promises. Optionally second `prototype` argument may be provided to be used - a prototype for a returned promise. - - ## Example - - var promise = promised(Array)(1, promise(2), promise(3)) - promise.then(console.log) // => [ 1, 2, 3 ] - **/ - - return function promised() { - // create array of [ f, this, args... ] - return concat.apply([ f, this ], arguments). - // reduce it via `promisedConcat` to get promised array of fulfillments - reduce(promisedConcat, resolve([], prototype)). - // finally map that to promise of `f.apply(this, args...)` - then(execute); - }; - } -})(); -exports.promised = promised; -// -var all = promised(Array); -exports.all = all; -// -//}); diff --git a/scripting/javascript/bindings/js/debugger/main.js b/scripting/javascript/bindings/js/debugger/main.js deleted file mode 100644 index f08009ade6..0000000000 --- a/scripting/javascript/bindings/js/debugger/main.js +++ /dev/null @@ -1,928 +0,0 @@ -/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -/** - * Toolkit glue for the remote debugging protocol, loaded into the - * debugging global. - */ - -//const Ci = Components.interfaces; -//const Cc = Components.classes; -//const CC = Components.Constructor; -//const Cu = Components.utils; -//const Cr = Components.results; -//const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties"; -// -//Cu.import("resource://gre/modules/Services.jsm"); -//Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -//let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log"); -// -//Cu.import("resource://gre/modules/jsdebugger.jsm"); -//addDebuggerToGlobal(this); -// -//Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); -//const { defer, resolve, reject, all } = Promise; -// -//Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); -// -//loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); - -let wantLogging = true; -let debuggerServer = null; - -function dumpn(str) { - if (wantLogging) { - log("DBG-SERVER: " + str + "\n"); - } -} - -function dbg_assert(cond, e) { - if (!cond) { - log("assert >>>> " + cond.toString()); - return e; - } -} - -function XPCInspector() { - this.exitNestedEventLoop = _exitNestedEventLoop; - this.enterNestedEventLoop = _enterNestedEventLoop; - this.eventLoopNestLevel = _getEventLoopNestLevel; -} - -//loadSubScript.call(this, "resource://gre/modules/devtools/server/transport.js"); - -// XPCOM constructors -// const ServerSocket = CC("@mozilla.org/network/server-socket;1", -// "nsIServerSocket", -// "initSpecialConnection"); - -function ServerSocket(aPort, flags, c){ - this.asyncListen = function(server){ - log("asyncListen...."); - debuggerServer = server; - }; -}; - -var gRegisteredModules = Object.create(null); - -/** - * The ModuleAPI object is passed to modules loaded using the - * DebuggerServer.registerModule() API. Modules can use this - * object to register actor factories. - * Factories registered through the module API will be removed - * when the module is unregistered or when the server is - * destroyed. - */ -function ModuleAPI() { - let activeTabActors = new Set(); - let activeGlobalActors = new Set(); - - return { - // See DebuggerServer.addGlobalActor for a description. - addGlobalActor: function(factory, name) { - DebuggerServer.addGlobalActor(factory, name); - activeGlobalActors.add(factory); - }, - // See DebuggerServer.removeGlobalActor for a description. - removeGlobalActor: function(factory) { - DebuggerServer.removeGlobalActor(factory); - activeGlobalActors.delete(factory); - }, - - // See DebuggerServer.addTabActor for a description. - addTabActor: function(factory, name) { - DebuggerServer.addTabActor(factory, name); - activeTabActors.add(factory); - }, - // See DebuggerServer.removeTabActor for a description. - removeTabActor: function(factory) { - DebuggerServer.removeTabActor(factory); - activeTabActors.delete(factory); - }, - - // Destroy the module API object, unregistering any - // factories registered by the module. - destroy: function() { - for (let factory of activeTabActors) { - DebuggerServer.removeTabActor(factory); - } - activeTabActors = null; - for (let factory of activeGlobalActors) { - DebuggerServer.removeGlobalActor(factory); - } - activeGlobalActors = null; - } - } -}; - -/*** - * Public API - */ -var DebuggerServer = { - _listener: null, - _initialized: false, - _transportInitialized: false, - xpcInspector: null, - _transport: null, - // Number of currently open TCP connections. - _socketConnections: 0, - // Map of global actor names to actor constructors provided by extensions. - globalActorFactories: {}, - // Map of tab actor names to actor constructors provided by extensions. - tabActorFactories: {}, - - LONG_STRING_LENGTH: 10000, - LONG_STRING_INITIAL_LENGTH: 1000, - LONG_STRING_READ_LENGTH: 1000, - - /** - * A handler function that prompts the user to accept or decline the incoming - * connection. - */ - _allowConnection: null, - - /** - * Prompt the user to accept or decline the incoming connection. This is the - * default implementation that products embedding the debugger server may - * choose to override. - * - * @return true if the connection should be permitted, false otherwise - */ - _defaultAllowConnection: function DS__defaultAllowConnection() { - // let title = L10N.getStr("remoteIncomingPromptTitle"); - // let msg = L10N.getStr("remoteIncomingPromptMessage"); - // let disableButton = L10N.getStr("remoteIncomingPromptDisable"); - // let prompt = Services.prompt; - // let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK + - // prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL + - // prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING + - // prompt.BUTTON_POS_1_DEFAULT; - // let result = prompt.confirmEx(null, title, msg, flags, null, null, - // disableButton, null, { value: false }); - // if (result == 0) { - // return true; - // } - // if (result == 2) { - // DebuggerServer.closeListener(true); - // Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false); - // } - // return false; - return true; - }, - - /** - * Initialize the debugger server. - * - * @param function aAllowConnectionCallback - * The embedder-provider callback, that decides whether an incoming - * remote protocol conection should be allowed or refused. - */ - init: function DS_init(aAllowConnectionCallback) { - if (this.initialized) { - return; - } - - this.xpcInspector = new XPCInspector();//Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); - this.initTransport(aAllowConnectionCallback); - this.addActors("resource://gre/modules/devtools/server/actors/root.js"); - - this._initialized = true; - }, - - /** - * Initialize the debugger server's transport variables. This can be - * in place of init() for cases where the jsdebugger isn't needed. - * - * @param function aAllowConnectionCallback - * The embedder-provider callback, that decides whether an incoming - * remote protocol conection should be allowed or refused. - */ - initTransport: function DS_initTransport(aAllowConnectionCallback) { - if (this._transportInitialized) { - return; - } - - this._connections = {}; - this._nextConnID = 0; - this._transportInitialized = true; - this._allowConnection = aAllowConnectionCallback ? - aAllowConnectionCallback : - this._defaultAllowConnection; - }, - - get initialized() this._initialized, - - /** - * Performs cleanup tasks before shutting down the debugger server, if no - * connections are currently open. Such tasks include clearing any actor - * constructors added at runtime. This method should be called whenever a - * debugger server is no longer useful, to avoid memory leaks. After this - * method returns, the debugger server must be initialized again before use. - */ - destroy: function DS_destroy() { - if (!this._initialized) { - return; - } - - for (let connID of Object.getOwnPropertyNames(this._connections)) { - this._connections[connID].close(); - } - - for (let id of Object.getOwnPropertyNames(gRegisteredModules)) { - let mod = gRegisteredModules[id]; - mod.module.unregister(mod.api); - } - gRegisteredModules = {}; - - this.closeListener(); - this.globalActorFactories = {}; - this.tabActorFactories = {}; - delete this._allowConnection; - this._transportInitialized = false; - this._initialized = false; - dumpn("Debugger server is shut down."); - }, - - /** - * Load a subscript into the debugging global. - * - * @param aURL string A url that will be loaded as a subscript into the - * debugging global. The user must load at least one script - * that implements a createRootActor() function to create the - * server's root actor. - */ - addActors: function DS_addActors(aURL) { - //loadSubScript.call(this, aURL); - }, - - /** - * Register a CommonJS module with the debugger server. - * @param id string - * The ID of a CommonJS module. This module must export - * 'register' and 'unregister' functions. - */ - registerModule: function(id) { - if (id in gRegisteredModules) { - throw new Error("Tried to register a module twice: " + id + "\n"); - } - - let moduleAPI = ModuleAPI(); - - let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); - let mod = devtools.require(id); - mod.register(moduleAPI); - gRegisteredModules[id] = { module: mod, api: moduleAPI }; - }, - - /** - * Returns true if a module id has been registered. - */ - isModuleRegistered: function(id) { - return (id in gRegisteredModules); - }, - - /** - * Unregister a previously-loaded CommonJS module from the debugger server. - */ - unregisterModule: function(id) { - let mod = gRegisteredModules[id]; - if (!mod) { - throw new Error("Tried to unregister a module that was not previously registered."); - } - mod.module.unregister(mod.api); - mod.api.destroy(); - delete gRegisteredModules[id]; - }, - - /** - * Install Firefox-specific actors. - */ - addBrowserActors: function DS_addBrowserActors() { - this.addActors("resource://gre/modules/devtools/server/actors/webbrowser.js"); - this.addActors("resource://gre/modules/devtools/server/actors/script.js"); - this.addGlobalActor(this.ChromeDebuggerActor, "chromeDebugger"); - this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js"); - this.addActors("resource://gre/modules/devtools/server/actors/gcli.js"); - if ("nsIProfiler" in Ci) - this.addActors("resource://gre/modules/devtools/server/actors/profiler.js"); - - this.addActors("resource://gre/modules/devtools/server/actors/styleeditor.js"); - this.addActors("resource://gre/modules/devtools/server/actors/webapps.js"); - this.registerModule("devtools/server/actors/inspector"); - }, - - /** - * Listens on the given port for remote debugger connections. - * - * @param aPort int - * The port to listen on. - */ - openListener: function DS_openListener(aPort) { - // if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) { - // return false; - // } - this._checkInit(); - - // Return early if the server is already listening. - if (this._listener) { - return true; - } - - // let flags = Ci.nsIServerSocket.KeepWhenOffline; - // A preference setting can force binding on the loopback interface. - // if (Services.prefs.getBoolPref("devtools.debugger.force-local")) { - // flags |= Ci.nsIServerSocket.LoopbackOnly; - // } - - let flags = 0; - - try { - let socket = new ServerSocket(aPort, flags, 4); - socket.asyncListen(this); - this._listener = socket; - } catch (e) { - dumpn("Could not start debugging listener on port " + aPort + ": " + e); - throw "Cr.NS_ERROR_NOT_AVAILABLE"; - } - this._socketConnections++; - - return true; - }, - - /** - * Close a previously-opened TCP listener. - * - * @param aForce boolean [optional] - * If set to true, then the socket will be closed, regardless of the - * number of open connections. - */ - closeListener: function DS_closeListener(aForce) { - if (!this._listener || this._socketConnections == 0) { - return false; - } - - // Only close the listener when the last connection is closed, or if the - // aForce flag is passed. - if (--this._socketConnections == 0 || aForce) { - this._listener.close(); - this._listener = null; - this._socketConnections = 0; - } - - return true; - }, - - /** - * Creates a new connection to the local debugger speaking over a fake - * transport. This connection results in straightforward calls to the onPacket - * handlers of each side. - * - * @returns a client-side DebuggerTransport for communicating with - * the newly-created connection. - */ - connectPipe: function DS_connectPipe() { - this._checkInit(); - - let serverTransport = new LocalDebuggerTransport; - let clientTransport = new LocalDebuggerTransport(serverTransport); - serverTransport.other = clientTransport; - let connection = this._onConnection(serverTransport); - - // I'm putting this here because I trust you. - // - // There are times, when using a local connection, when you're going - // to be tempted to just get direct access to the server. Resist that - // temptation! If you succumb to that temptation, you will make the - // fine developers that work on Fennec and Firefox OS sad. They're - // professionals, they'll try to act like they understand, but deep - // down you'll know that you hurt them. - // - // This reference allows you to give in to that temptation. There are - // times this makes sense: tests, for example, and while porting a - // previously local-only codebase to the remote protocol. - // - // But every time you use this, you will feel the shame of having - // used a property that starts with a '_'. - clientTransport._serverConnection = connection; - - return clientTransport; - }, - - - // nsIServerSocketListener implementation - - onSocketAccepted: - makeInfallible(function DS_onSocketAccepted(aSocket, aTransport) { - if (!this._allowConnection()) { - return; - } - dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port); - - let input = aTransport.openInputStream(0, 0, 0); - let output = aTransport.openOutputStream(0, 0, 0); - let transport = new DebuggerTransport(input, output); - DebuggerServer._onConnection(transport); - }, "DebuggerServer.onSocketAccepted"), - - onStopListening: function DS_onStopListening(aSocket, status) { - dumpn("onStopListening, status: " + status); - }, - - /** - * Raises an exception if the server has not been properly initialized. - */ - _checkInit: function DS_checkInit() { - if (!this._transportInitialized) { - throw "DebuggerServer has not been initialized."; - } - - if (!this.createRootActor) { - throw "Use DebuggerServer.addActors() to add a root actor implementation."; - } - }, - - /** - * Create a new debugger connection for the given transport. Called - * after connectPipe() or after an incoming socket connection. - */ - _onConnection: function DS_onConnection(aTransport) { - log("DebuggerServer._onConnection...."); - - this._transport = aTransport; - - let connID = "conn" + this._nextConnID++ + '.'; - let conn = new DebuggerServerConnection(connID, aTransport); - this._connections[connID] = conn; - - // Create a root actor for the connection and send the hello packet. - conn.rootActor = this.createRootActor(conn); - conn.addActor(conn.rootActor); - - aTransport.send(conn.rootActor.sayHello()); - aTransport.ready(); - - return conn; - }, - - /** - * Remove the connection from the debugging server. - */ - _connectionClosed: function DS_connectionClosed(aConnection) { - delete this._connections[aConnection.prefix]; - }, - - // DebuggerServer extension API. - - /** - * Registers handlers for new tab-scoped request types defined dynamically. - * This is used for example by add-ons to augment the functionality of the tab - * actor. Note that the name or actorPrefix of the request type is not allowed - * to clash with existing protocol packet properties, like 'title', 'url' or - * 'actor', since that would break the protocol. - * - * @param aFunction function - * The constructor function for this request type. This expects to be - * called as a constructor (i.e. with 'new'), and passed two - * arguments: the DebuggerServerConnection, and the BrowserTabActor - * with which it will be associated. - * - * @param aName string [optional] - * The name of the new request type. If this is not present, the - * actorPrefix property of the constructor prototype is used. - */ - addTabActor: function DS_addTabActor(aFunction, aName) { - let name = aName ? aName : aFunction.prototype.actorPrefix; - if (["title", "url", "actor"].indexOf(name) != -1) { - throw Error(name + " is not allowed"); - } - if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) { - throw Error(name + " already exists"); - } - DebuggerServer.tabActorFactories[name] = aFunction; - }, - - /** - * Unregisters the handler for the specified tab-scoped request type. - * This may be used for example by add-ons when shutting down or upgrading. - * - * @param aFunction function - * The constructor function for this request type. - */ - removeTabActor: function DS_removeTabActor(aFunction) { - for (let name in DebuggerServer.tabActorFactories) { - let handler = DebuggerServer.tabActorFactories[name]; - if (handler.name == aFunction.name) { - delete DebuggerServer.tabActorFactories[name]; - } - } - }, - - /** - * Registers handlers for new browser-scoped request types defined - * dynamically. This is used for example by add-ons to augment the - * functionality of the root actor. Note that the name or actorPrefix of the - * request type is not allowed to clash with existing protocol packet - * properties, like 'from', 'tabs' or 'selected', since that would break the - * protocol. - * - * @param aFunction function - * The constructor function for this request type. This expects to be - * called as a constructor (i.e. with 'new'), and passed two - * arguments: the DebuggerServerConnection, and the BrowserRootActor - * with which it will be associated. - * - * @param aName string [optional] - * The name of the new request type. If this is not present, the - * actorPrefix property of the constructor prototype is used. - */ - addGlobalActor: function DS_addGlobalActor(aFunction, aName) { - let name = aName ? aName : aFunction.prototype.actorPrefix; - if (["from", "tabs", "selected"].indexOf(name) != -1) { - throw Error(name + " is not allowed"); - } - if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) { - throw Error(name + " already exists"); - } - DebuggerServer.globalActorFactories[name] = aFunction; - }, - - /** - * Unregisters the handler for the specified browser-scoped request type. - * This may be used for example by add-ons when shutting down or upgrading. - * - * @param aFunction function - * The constructor function for this request type. - */ - removeGlobalActor: function DS_removeGlobalActor(aFunction) { - for (let name in DebuggerServer.globalActorFactories) { - let handler = DebuggerServer.globalActorFactories[name]; - if (handler.name == aFunction.name) { - delete DebuggerServer.globalActorFactories[name]; - } - } - } -}; - - -/** - * Construct an ActorPool. - * - * ActorPools are actorID -> actor mapping and storage. These are - * used to accumulate and quickly dispose of groups of actors that - * share a lifetime. - */ -function ActorPool(aConnection) -{ - this.conn = aConnection; - this._cleanups = {}; - this._actors = {}; -} - -ActorPool.prototype = { - /** - * Add an actor to the actor pool. If the actor doesn't have an ID, - * allocate one from the connection. - * - * @param aActor object - * The actor implementation. If the object has a - * 'disconnect' property, it will be called when the actor - * pool is cleaned up. - */ - addActor: function AP_addActor(aActor) { - aActor.conn = this.conn; - if (!aActor.actorID) { - let prefix = aActor.actorPrefix; - if (typeof aActor == "function") { - prefix = aActor.prototype.actorPrefix; - } - aActor.actorID = this.conn.allocID(prefix || undefined); - } - - if (aActor.registeredPool) { - aActor.registeredPool.removeActor(aActor); - } - aActor.registeredPool = this; - - this._actors[aActor.actorID] = aActor; - if (aActor.disconnect) { - this._cleanups[aActor.actorID] = aActor; - } - }, - - get: function AP_get(aActorID) { - return this._actors[aActorID]; - }, - - has: function AP_has(aActorID) { - return aActorID in this._actors; - }, - - /** - * Returns true if the pool is empty. - */ - isEmpty: function AP_isEmpty() { - return Object.keys(this._actors).length == 0; - }, - - /** - * Remove an actor from the actor pool. - */ - removeActor: function AP_remove(aActor) { - delete this._actors[aActor.actorID]; - delete this._cleanups[aActor.actorID]; - }, - - /** - * Match the api expected by the protocol library. - */ - unmanage: function(aActor) { - return this.removeActor(aActor); - }, - - /** - * Run all actor cleanups. - */ - cleanup: function AP_cleanup() { - for each (let actor in this._cleanups) { - actor.disconnect(); - } - this._cleanups = {}; - } -} - -/** - * Creates a DebuggerServerConnection. - * - * Represents a connection to this debugging global from a client. - * Manages a set of actors and actor pools, allocates actor ids, and - * handles incoming requests. - * - * @param aPrefix string - * All actor IDs created by this connection should be prefixed - * with aPrefix. - * @param aTransport transport - * Packet transport for the debugging protocol. - */ -function DebuggerServerConnection(aPrefix, aTransport) -{ - this._prefix = aPrefix; - this._transport = aTransport; - this._transport.hooks = this; - this._nextID = 1; - - this._actorPool = new ActorPool(this); - this._extraPools = []; -} - -DebuggerServerConnection.prototype = { - _prefix: null, - get prefix() { return this._prefix }, - - _transport: null, - get transport() { return this._transport }, - - close: function() { - this._transport.close(); - }, - - send: function DSC_send(aPacket) { - this.transport.send(aPacket); - }, - - allocID: function DSC_allocID(aPrefix) { - return this.prefix + (aPrefix || '') + this._nextID++; - }, - - /** - * Add a map of actor IDs to the connection. - */ - addActorPool: function DSC_addActorPool(aActorPool) { - this._extraPools.push(aActorPool); - }, - - /** - * Remove a previously-added pool of actors to the connection. - * - * @param ActorPool aActorPool - * The ActorPool instance you want to remove. - * @param boolean aCleanup - * True if you want to disconnect each actor from the pool, false - * otherwise. - */ - removeActorPool: function DSC_removeActorPool(aActorPool, aCleanup) { - let index = this._extraPools.lastIndexOf(aActorPool); - if (index > -1) { - let pool = this._extraPools.splice(index, 1); - if (aCleanup) { - pool.map(function(p) { p.cleanup(); }); - } - } - }, - - /** - * Add an actor to the default actor pool for this connection. - */ - addActor: function DSC_addActor(aActor) { - this._actorPool.addActor(aActor); - }, - - /** - * Remove an actor to the default actor pool for this connection. - */ - removeActor: function DSC_removeActor(aActor) { - this._actorPool.removeActor(aActor); - }, - - /** - * Match the api expected by the protocol library. - */ - unmanage: function(aActor) { - return this.removeActor(aActor); - }, - - /** - * Look up an actor implementation for an actorID. Will search - * all the actor pools registered with the connection. - * - * @param aActorID string - * Actor ID to look up. - */ - getActor: function DSC_getActor(aActorID) { - let pool = this.poolFor(aActorID); - if (pool) { - return pool.get(aActorID); - } - - if (aActorID === "root") { - return this.rootActor; - } - - return null; - }, - - poolFor: function DSC_actorPool(aActorID) { - if (this._actorPool && this._actorPool.has(aActorID)) { - return this._actorPool; - } - - for (let pool of this._extraPools) { - if (pool.has(aActorID)) { - return pool; - } - } - return null; - }, - - _unknownError: function DSC__unknownError(aPrefix, aError) { - let errorString = safeErrorString(aError); - errorString += "\n" + aError.stack; - // Cu.reportError(errorString); - dumpn(errorString); - return { - error: "unknownError", - message: (aPrefix + "': " + errorString) - }; - }, - - // Transport hooks. - - /** - * Called by DebuggerTransport to dispatch incoming packets as appropriate. - * - * @param aPacket object - * The incoming packet. - */ - onPacket: function DSC_onPacket(aPacket) { - let actor = this.getActor(aPacket.to); - if (!actor) { - this.transport.send({ from: aPacket.to ? aPacket.to : "root", - error: "noSuchActor" }); - return; - } - - // Dyamically-loaded actors have to be created lazily. - if (typeof actor == "function") { - let instance; - try { - instance = new actor(); - } catch (e) { - this.transport.send(this._unknownError( - "Error occurred while creating actor '" + actor.name, - e)); - } - instance.parentID = actor.parentID; - // We want the newly-constructed actor to completely replace the factory - // actor. Reusing the existing actor ID will make sure ActorPool.addActor - // does the right thing. - instance.actorID = actor.actorID; - actor.registeredPool.addActor(instance); - actor = instance; - } - - var ret = null; - // log("actor.requestTypes: "+actor.requestTypes+", cb: "+actor.requestTypes[aPacket.type]); - // Dispatch the request to the actor. - if (actor.requestTypes && actor.requestTypes[aPacket.type]) { - try { - this.currentPacket = aPacket; - ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket, this); - } catch(e) { - this.transport.send(this._unknownError( - "error occurred while processing '" + aPacket.type, - e)); - } finally { - delete this.currentPacket; - } - } else { - ret = { error: "unrecognizedPacketType", - message: ('Actor "' + actor.actorID + - '" does not recognize the packet type "' + - aPacket.type + '"') }; - } - - if (!ret) { - // This should become an error once we've converted every user - // of this to promises in bug 794078. - return; - } - - resolve(ret) - .then(null, (e) => { - return this._unknownError( - "error occurred while processing '" + aPacket.type, - e); - }) - .then(function (aResponse) { - if (!aResponse.from) { - aResponse.from = aPacket.to; - } - return aResponse; - }) - .then(this.transport.send.bind(this.transport)); - }, - - /** - * Called by DebuggerTransport when the underlying stream is closed. - * - * @param aStatus nsresult - * The status code that corresponds to the reason for closing - * the stream. - */ - onClosed: function DSC_onClosed(aStatus) { - dumpn("Cleaning up connection."); - - this._actorPool.cleanup(); - this._actorPool = null; - this._extraPools.map(function(p) { p.cleanup(); }); - this._extraPools = null; - - DebuggerServer._connectionClosed(this); - }, - - /* - * Debugging helper for inspecting the state of the actor pools. - */ - _dumpPools: function DSC_dumpPools() { - dumpn("/-------------------- dumping pools:"); - if (this._actorPool) { - dumpn("--------------------- actorPool actors: " + - uneval(Object.keys(this._actorPool._actors))); - } - for each (let pool in this._extraPools) - dumpn("--------------------- extraPool actors: " + - uneval(Object.keys(pool._actors))); - }, - - /* - * Debugging helper for inspecting the state of an actor pool. - */ - _dumpPool: function DSC_dumpPools(aPool) { - dumpn("/-------------------- dumping pool:"); - dumpn("--------------------- actorPool actors: " + - uneval(Object.keys(aPool._actors))); - } -}; - -/** - * Localization convenience methods. - */ -// let L10N = { - -// /** -// * L10N shortcut function. -// * -// * @param string aName -// * @return string -// */ -// getStr: function L10N_getStr(aName) { -// return this.stringBundle.GetStringFromName(aName); -// } -// }; - -// XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() { -// return Services.strings.createBundle(DBG_STRINGS_URI); -// }); diff --git a/scripting/javascript/bindings/js/debugger/transport.js b/scripting/javascript/bindings/js/debugger/transport.js deleted file mode 100644 index 8676e367a8..0000000000 --- a/scripting/javascript/bindings/js/debugger/transport.js +++ /dev/null @@ -1,288 +0,0 @@ -/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -// Components.utils.import("resource://gre/modules/NetUtil.jsm"); - -/** - * An adapter that handles data transfers between the debugger client and - * server. It can work with both nsIPipe and nsIServerSocket transports so - * long as the properly created input and output streams are specified. - * - * @param aInput nsIInputStream - * The input stream. - * @param aOutput nsIAsyncOutputStream - * The output stream. - * - * Given a DebuggerTransport instance dt: - * 1) Set dt.hooks to a packet handler object (described below). - * 2) Call dt.ready() to begin watching for input packets. - * 3) Send packets as you please, and handle incoming packets passed to - * hook.onPacket. - * 4) Call dt.close() to close the connection, and disengage from the event - * loop. - * - * A packet handler object is an object with two methods: - * - * - onPacket(packet) - called when we have received a complete packet. - * |Packet| is the parsed form of the packet --- a JavaScript value, not - * a JSON-syntax string. - * - * - onClosed(status) - called when the connection is closed. |Status| is - * an nsresult, of the sort passed to nsIRequestObserver. - * - * Data is transferred as a JSON packet serialized into a string, with the - * string length prepended to the packet, followed by a colon - * ([length]:[packet]). The contents of the JSON packet are specified in - * the Remote Debugging Protocol specification. - */ -this.DebuggerTransport = function DebuggerTransport(aInput, aOutput) -{ - this._input = aInput; - this._output = aOutput; - - this._converter = null;//Cc["@mozilla.org/intl/scriptableunicodeconverter"] - // .createInstance(Ci.nsIScriptableUnicodeConverter); - // this._converter.charset = "UTF-8"; - - this._outgoing = ""; - this._incoming = ""; - - this.hooks = null; -} - -DebuggerTransport.prototype = { - /** - * Transmit a packet. - * - * This method returns immediately, without waiting for the entire - * packet to be transmitted, registering event handlers as needed to - * transmit the entire packet. Packets are transmitted in the order - * they are passed to this method. - */ - send: function DT_send(aPacket) { - // TODO (bug 709088): remove pretty printing when the protocol is done. - let data = JSON.stringify(aPacket, null, 2); - // data = this._converter.ConvertFromUnicode(data); - - let data_for_len = utf16to8(data); - - this._outgoing = data_for_len.length + ':' + data; - - this._flushOutgoing(); - }, - - /** - * Close the transport. - */ - close: function DT_close() { - this._input.close(); - this._output.close(); - }, - - /** - * Flush the outgoing stream. - */ - _flushOutgoing: function DT_flushOutgoing() { - if (this._outgoing.length > 0) { - // var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(); - // this._output.asyncWait(this, 0, 0, threadManager.currentThread); - log("outgoing: " + this._outgoing);//.substring(0, 200)); - _bufferWrite(this._outgoing); - } - }, - - onOutputStreamReady: - makeInfallible(function DT_onOutputStreamReady(aStream) { - let written = 0; - try { - written = aStream.write(this._outgoing, this._outgoing.length); - } catch(e if e.result == Components.results.NS_BASE_STREAM_CLOSED) { - dumpn("Connection closed."); - this.close(); - return; - } - this._outgoing = this._outgoing.slice(written); - this._flushOutgoing(); - }, "DebuggerTransport.prototype.onOutputStreamReady"), - - /** - * Initialize the input stream for reading. Once this method has been - * called, we watch for packets on the input stream, and pass them to - * this.hook.onPacket. - */ - ready: function DT_ready() { - // let pump = Cc["@mozilla.org/network/input-stream-pump;1"] - // .createInstance(Ci.nsIInputStreamPump); - // pump.init(this._input, -1, -1, 0, 0, false); - // pump.asyncRead(this, null); - }, - - // nsIStreamListener - onStartRequest: - makeInfallible(function DT_onStartRequest(aRequest, aContext) {}, - "DebuggerTransport.prototype.onStartRequest"), - - onStopRequest: - makeInfallible(function DT_onStopRequest(aRequest, aContext, aStatus) { - this.close(); - if (this.hooks) { - this.hooks.onClosed(aStatus); - this.hooks = null; - } - }, "DebuggerTransport.prototype.onStopRequest"), - - onDataAvailable: makeInfallible(function DT_onDataAvailable (incoming) -// makeInfallible(function DT_onDataAvailable(aRequest, aContext, -// aStream, aOffset, aCount) - { - this._incoming = incoming;//+= NetUtil.readInputStreamToString(aStream, - // aStream.available()); - while (this._processIncoming()) {}; - }, "DebuggerTransport.prototype.onDataAvailable"), - - /** - * Process incoming packets. Returns true if a packet has been received, either - * if it was properly parsed or not. Returns false if the incoming stream does - * not contain a full packet yet. After a proper packet is parsed, the dispatch - * handler DebuggerTransport.hooks.onPacket is called with the packet as a - * parameter. - */ - _processIncoming: function DT__processIncoming() { - // Well this is ugly. - let sep = this._incoming.indexOf(':'); - if (sep < 0) { - return false; - } - - let count = parseInt(this._incoming.substring(0, sep)); - if (this._incoming.length - (sep + 1) < count) { - // Don't have a complete request yet. - return false; - } - - // We have a complete request, pluck it out of the data and parse it. - this._incoming = this._incoming.substring(sep + 1); - let packet = this._incoming.substring(0, count); - this._incoming = this._incoming.substring(count); - - try { - // packet = this._converter.ConvertToUnicode(packet); - packet = utf8to16(packet); - var parsed = JSON.parse(packet); - } catch(e) { - let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")"; - // if (Cu.reportError) { - // Cu.reportError(msg); - // } - dump(msg + "\n"); - return true; - } - - dumpn("Got: " + packet); - let self = this; - - // Services.tm.currentThread.dispatch(makeInfallible(function() { - self.hooks.onPacket(parsed); - // }, "DebuggerTransport instance's this.hooks.onPacket"), 0); - - return true; - } -} - - -/** - * An adapter that handles data transfers between the debugger client and - * server when they both run in the same process. It presents the same API as - * DebuggerTransport, but instead of transmitting serialized messages across a - * connection it merely calls the packet dispatcher of the other side. - * - * @param aOther LocalDebuggerTransport - * The other endpoint for this debugger connection. - * - * @see DebuggerTransport - */ -this.LocalDebuggerTransport = function LocalDebuggerTransport(aOther) -{ - this.other = aOther; - this.hooks = null; - - /* - * A packet number, shared between this and this.other. This isn't used - * by the protocol at all, but it makes the packet traces a lot easier to - * follow. - */ - this._serial = this.other ? this.other._serial : { count: 0 }; -} - -LocalDebuggerTransport.prototype = { - /** - * Transmit a message by directly calling the onPacket handler of the other - * endpoint. - */ - send: function LDT_send(aPacket) { - let serial = this._serial.count++; - if (wantLogging) { - if (aPacket.to) { - dumpn("Packet " + serial + " sent to " + uneval(aPacket.to)); - } else if (aPacket.from) { - dumpn("Packet " + serial + " sent from " + uneval(aPacket.from)); - } - } - this._deepFreeze(aPacket); - let other = this.other; - if (other) { - Services.tm.currentThread.dispatch(makeInfallible(function() { - // Avoid the cost of JSON.stringify() when logging is disabled. - if (wantLogging) { - dumpn("Received packet " + serial + ": " + JSON.stringify(aPacket, null, 2)); - } - if (other.hooks) { - other.hooks.onPacket(aPacket); - } - }, "LocalDebuggerTransport instance's this.other.hooks.onPacket"), 0); - } - }, - - /** - * Close the transport. - */ - close: function LDT_close() { - if (this.other) { - // Remove the reference to the other endpoint before calling close(), to - // avoid infinite recursion. - let other = this.other; - delete this.other; - other.close(); - } - if (this.hooks) { - this.hooks.onClosed(); - this.hooks = null; - } - }, - - /** - * An empty method for emulating the DebuggerTransport API. - */ - ready: function LDT_ready() {}, - - /** - * Helper function that makes an object fully immutable. - */ - _deepFreeze: function LDT_deepFreeze(aObject) { - Object.freeze(aObject); - for (let prop in aObject) { - // Freeze the properties that are objects, not on the prototype, and not - // already frozen. Note that this might leave an unfrozen reference - // somewhere in the object if there is an already frozen object containing - // an unfrozen object. - if (aObject.hasOwnProperty(prop) && typeof aObject === "object" && - !Object.isFrozen(aObject)) { - this._deepFreeze(o[prop]); - } - } - } -}; diff --git a/scripting/lua/proj.emscripten/Makefile b/scripting/lua/proj.emscripten/Makefile deleted file mode 100644 index 5c978d7a0f..0000000000 --- a/scripting/lua/proj.emscripten/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -TARGET = liblua.so - -INCLUDES += -I.. -I../lua -I../tolua -I../cocos2dx_support -I../../auto-generated/lua-bindings \ - -I../Classes -I../../../CocosDenshion/include -I../../../extensions - -SOURCES = ../lua/lapi.c \ - ../lua/lauxlib.c \ - ../lua/lbaselib.c \ - ../lua/lcode.c \ - ../lua/ldblib.c \ - ../lua/ldebug.c \ - ../lua/ldo.c \ - ../lua/ldump.c \ - ../lua/lfunc.c \ - ../lua/lgc.c \ - ../lua/linit.c \ - ../lua/liolib.c \ - ../lua/llex.c \ - ../lua/lmathlib.c \ - ../lua/lmem.c \ - ../lua/loadlib.c \ - ../lua/lobject.c \ - ../lua/lopcodes.c \ - ../lua/loslib.c \ - ../lua/lparser.c \ - ../lua/lstate.c \ - ../lua/lstring.c \ - ../lua/lstrlib.c \ - ../lua/ltable.c \ - ../lua/ltablib.c \ - ../lua/ltm.c \ - ../lua/lundump.c \ - ../lua/lvm.c \ - ../lua/lzio.c \ - ../lua/print.c \ - ../tolua/tolua_event.c \ - ../tolua/tolua_is.c \ - ../tolua/tolua_map.c \ - ../tolua/tolua_push.c \ - ../tolua/tolua_to.c \ - ../cocos2dx_support/tolua_fix.c \ - ../../auto-generated/lua-bindings/lua_cocos2dx_auto.cpp \ - ../../auto-generated/lua-bindings/lua_cocos2dx_extension_auto.cpp \ - ../cocos2dx_support/CCLuaBridge.cpp \ - ../cocos2dx_support/CCLuaEngine.cpp \ - ../cocos2dx_support/CCLuaStack.cpp \ - ../cocos2dx_support/CCLuaValue.cpp \ - ../cocos2dx_support/Cocos2dxLuaLoader.cpp \ - ../cocos2dx_support/CCBProxy.cpp \ - ../cocos2dx_support/LuaOpengl.cpp \ - ../cocos2dx_support/LuaScriptHandlerMgr.cpp \ - ../cocos2dx_support/LuaBasicConversions.cpp \ - ../cocos2dx_support/lua_cocos2dx_manual.cpp \ - ../cocos2dx_support/lua_cocos2dx_extension_manual.cpp \ - ../cocos2dx_support/lua_cocos2dx_deprecated.cpp - -include ../../../cocos2dx/proj.emscripten/cocos2dx.mk - -TARGET := $(LIB_DIR)/$(TARGET) - -all: $(TARGET) - -$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(OBJECTS) -shared -o $@ $(SHAREDLIBS) $(STATICLIBS) - -$(OBJ_DIR)/%.o: ../../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ - -$(OBJ_DIR)/%.o: ../%.c $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(CC) $(CCFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/scripting/lua/proj.nacl/Makefile b/scripting/lua/proj.nacl/Makefile deleted file mode 100644 index 2a5c081487..0000000000 --- a/scripting/lua/proj.nacl/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -INCLUDES = -I.. -I../lua -I../../../extensions -I../../../external/chipmunk/include/chipmunk - -SOURCES = ../lua/lapi.c \ - ../lua/lauxlib.c \ - ../lua/lbaselib.c \ - ../lua/lcode.c \ - ../lua/ldblib.c \ - ../lua/ldebug.c \ - ../lua/ldo.c \ - ../lua/ldump.c \ - ../lua/lfunc.c \ - ../lua/lgc.c \ - ../lua/linit.c \ - ../lua/liolib.c \ - ../lua/llex.c \ - ../lua/lmathlib.c \ - ../lua/lmem.c \ - ../lua/loadlib.c \ - ../lua/lobject.c \ - ../lua/lopcodes.c \ - ../lua/loslib.c \ - ../lua/lparser.c \ - ../lua/lstate.c \ - ../lua/lstring.c \ - ../lua/lstrlib.c \ - ../lua/ltable.c \ - ../lua/ltablib.c \ - ../lua/ltm.c \ - ../lua/lundump.c \ - ../lua/lvm.c \ - ../lua/lzio.c \ - ../lua/print.c \ - ../tolua/tolua_event.c \ - ../tolua/tolua_is.c \ - ../tolua/tolua_map.c \ - ../tolua/tolua_push.c \ - ../tolua/tolua_to.c - -COCOS_ROOT = ../../.. - -include $(COCOS_ROOT)/cocos2dx/proj.nacl/cocos2dx.mk - -CCFLAGS = -Wno-uninitialized - -TARGET = $(LIB_DIR)/liblua.a -all: $(TARGET) - -$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) - $(LOG_AR)$(NACL_AR) $(ARFLAGS) $(TARGET) $(OBJECTS) - -$(OBJ_DIR)/%.o: ../%.c $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CC)$(NACL_CC) -MMD $(CCFLAGS) $(INCLUDES) $(DEFINES) $(VISIBILITY) -c $< -o $@ - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(NACL_CXX) -MMD $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/scripting/lua/proj.qt5/lua.pro b/scripting/lua/proj.qt5/lua.pro deleted file mode 100644 index c6a146d36e..0000000000 --- a/scripting/lua/proj.qt5/lua.pro +++ /dev/null @@ -1,33 +0,0 @@ - -include(../../../cocos2dx/proj.qt5/common.pri) - -TEMPLATE = lib -CONFIG += static -CONFIG += c++11 - -SOURCES += $$files(../lua/*.c) -SOURCES += $$files(../tolua/*.c) -SOURCES += $$files(../cocos2dx_support/*.c) -SOURCES += $$files(../cocos2dx_support/*.cpp) -SOURCES += $$files(../cocos2dx_support/generated/*.cpp) - -DEFINES += CC_TARGET_OS_MAC - -INCLUDEPATH += .. -INCLUDEPATH += ../lua -INCLUDEPATH += ../tolua -INCLUDEPATH += ../Classes -INCLUDEPATH += ../../../CocosDenshion/include -INCLUDEPATH += ../../../extensions -INCLUDEPATH += ../../../external/chipmunk/include/chipmunk -INCLUDEPATH += ../../../cocos2dx/include -INCLUDEPATH += ../../../cocos2dx -INCLUDEPATH += ../../../cocos2dx/platform/qt5 -INCLUDEPATH += ../../../cocos2dx/kazmath/include -INCLUDEPATH += ../cocos2dx_support -INCLUDEPATH += ../cocos2dx_support/generated - -# XXX SHAREDLIBS += -lextension - -TARGET = $${LIB_OUTPUT_DIR}/lua - diff --git a/scripting/lua/proj.tizen/.cproject b/scripting/lua/proj.tizen/.cproject deleted file mode 100644 index 115700b2ea..0000000000 --- a/scripting/lua/proj.tizen/.cproject +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripting/lua/proj.tizen/.project b/scripting/lua/proj.tizen/.project deleted file mode 100644 index 63ebdf667e..0000000000 --- a/scripting/lua/proj.tizen/.project +++ /dev/null @@ -1,106 +0,0 @@ - - - lua - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - sbi-make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/${ProjName}/Debug-Tizen-Emulator} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - org.tizen.nativecpp.apichecker.core.builder - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - org.tizen.nativecpp.apichecker.core.tizenCppNature - - - - src/cocos2dx_support - 2 - PARENT-1-PROJECT_LOC/cocos2dx_support - - - src/lua - 2 - PARENT-1-PROJECT_LOC/lua - - - src/tolua - 2 - PARENT-1-PROJECT_LOC/tolua - - - diff --git a/scripting/lua/proj.tizen/src/placeholder.txt b/scripting/lua/proj.tizen/src/placeholder.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/android-buildsetup.sh b/tools/android-buildsetup.sh deleted file mode 100755 index 1854d99b4d..0000000000 --- a/tools/android-buildsetup.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# Set up this cocos2d-x directory to build the Android port -# -# 1. Generate local.properties where necessary -# The END - -# exit this script if any commmand fails -set -e - -# read user.cfg if it exists and is readable - -_CFG_FILE=$(dirname "$0")"/user.cfg" -if [ -f "$_CFG_FILE" ] -then - [ -r "$_CFG_FILE" ] || die "Fatal Error: $_CFG_FILE exists but is unreadable" - . "$_CFG_FILE" -fi - -# paths - -if [ -z "${ANDROID_SDK_ROOT+aaa}" ]; then -# ... if ANDROID_SDK_ROOT is not set, use "$HOME/bin/android-sdk" - ANDROID_SDK_ROOT="$HOME/bin/android-sdk" -fi - -if [ -z "${ANDROID_NDK_ROOT+aaa}" ]; then -# ... if ANDROID_NDK_ROOT is not set, use "$HOME/bin/android-ndk" - ANDROID_NDK_ROOT="$HOME/bin/android-ndk" -fi - -# find current dir -SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# find working dir -WORKINGDIR="$(pwd)" - -# paths with defaults hardcoded to relative paths - -if [ -z "${COCOS2DX_ROOT+aaa}" ]; then - COCOS2DX_ROOT="$WORKINGDIR" -fi - -if [ ! -f "$COCOS2DX_ROOT/tools/android-buildsetup.sh" ] -then - echo "Run..." - echo "> ./tools/android-buildsetup.sh" - echo "... from the top level of the cocos2d-x source tree" - echo "OR" - echo "Run..." - echo "> COCOS2DX_ROOT= /build/setupandroid.sh" - exit -1 -fi - -echo "Paths :" -echo " ANDROID_SDK_ROOT: $ANDROID_SDK_ROOT" -echo " ANDROID_NDK_ROOT: $ANDROID_NDK_ROOT" -echo " COCOS2DX_ROOT : $COCOS2DX_ROOT" -echo " WORKINGDIR : $WORKINGDIR" -echo " SCRIPTDIR : $SCRIPTDIR" - -_CONTENTS="" -_CONTENTS+="sdk.dir=$ANDROID_SDK_ROOT"'\n' -_CONTENTS+="NDK_ROOT=$ANDROID_NDK_ROOT"'\n' -echo -echo "--- local.properties" -echo "---" -echo -e "$_CONTENTS" -echo "---" - -_ANDROIDMANIFESTS=(`find "$COCOS2DX_ROOT/cocos2dx" -type f -name "AndroidManifest.xml"`) -_ANDROIDMANIFESTS+=(`find "$COCOS2DX_ROOT/samples" -type f -name "AndroidManifest.xml"`) - -for a in "${_ANDROIDMANIFESTS[@]}"; do - _LOCAL_PROPERTIES_FILE=${a/AndroidManifest\.xml/local\.properties} - -# write local.properties if it doesn't already exist - if [ -f "$_LOCAL_PROPERTIES_FILE" ] - then - echo "$_LOCAL_PROPERTIES_FILE exists. skipping overwrite" - else - echo "writing $_LOCAL_PROPERTIES_FILE" - echo -e "$_CONTENTS" > "$_LOCAL_PROPERTIES_FILE" - fi -done diff --git a/tools/android_mk_generator/android_mk_generator.py b/tools/android-mk-generator/android_mk_generator.py similarity index 100% rename from tools/android_mk_generator/android_mk_generator.py rename to tools/android-mk-generator/android_mk_generator.py diff --git a/tools/android_mk_generator/config.py b/tools/android-mk-generator/config.py similarity index 100% rename from tools/android_mk_generator/config.py rename to tools/android-mk-generator/config.py diff --git a/tools/emscripten-templates/basic/index.html b/tools/emscripten-templates/basic/index.html deleted file mode 100644 index 2a30217165..0000000000 --- a/tools/emscripten-templates/basic/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - JS_APPLICATION generated by emscripten - - - -
- Cocos2d-x -

JS_APPLICATION

-
-
- Downloading... -
-
-

WebGL Error

-

WebGL is not supported by your browser.

-
-
-

Default quality

- Not ready yet - GO! -
-
-
- -
-
- Resize canvas - Lock/hide mouse pointer -     - -
- - - - - diff --git a/tools/emscripten-templates/iphone-ipad-ipadhd/index.html b/tools/emscripten-templates/iphone-ipad-ipadhd/index.html deleted file mode 100644 index b19939e956..0000000000 --- a/tools/emscripten-templates/iphone-ipad-ipadhd/index.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - JS_APPLICATION generated by emscripten - - - -
- Cocos2d-x -

JS_APPLICATION

-
-
- Downloading... -
-
-

WebGL Error

-

WebGL is not supported by your browser.

-
-
-

IPad HD quality

-

2048×1536px

- Not ready yet - GO! -
-
-

IPad quality

-

1024×768px

- Not ready yet - GO! -
-
-

IPhone quality

-

480×320px

- Not ready yet - GO! -
-
- - -
-
-
- -
-
- Resize canvas - Lock/hide mouse pointer -     - -
- - - - - diff --git a/tools/jenkins_scripts/Monkeyrunner_TestCpp.py b/tools/jenkins-scripts/Monkeyrunner_TestCpp.py similarity index 100% rename from tools/jenkins_scripts/Monkeyrunner_TestCpp.py rename to tools/jenkins-scripts/Monkeyrunner_TestCpp.py diff --git a/tools/jenkins_scripts/ReportManager.py b/tools/jenkins-scripts/ReportManager.py similarity index 100% rename from tools/jenkins_scripts/ReportManager.py rename to tools/jenkins-scripts/ReportManager.py diff --git a/tools/jenkins_scripts/ant.properties b/tools/jenkins-scripts/ant.properties similarity index 100% rename from tools/jenkins_scripts/ant.properties rename to tools/jenkins-scripts/ant.properties diff --git a/tools/jenkins_scripts/build.xml b/tools/jenkins-scripts/build.xml similarity index 100% rename from tools/jenkins_scripts/build.xml rename to tools/jenkins-scripts/build.xml diff --git a/tools/jenkins_scripts/mac/android/build-android-2.2-3.2-debug.sh b/tools/jenkins-scripts/mac/android/build-android-2.2-3.2-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/build-android-2.2-3.2-debug.sh rename to tools/jenkins-scripts/mac/android/build-android-2.2-3.2-debug.sh diff --git a/tools/jenkins_scripts/mac/android/build-android-2.2-3.2-release.sh b/tools/jenkins-scripts/mac/android/build-android-2.2-3.2-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/build-android-2.2-3.2-release.sh rename to tools/jenkins-scripts/mac/android/build-android-2.2-3.2-release.sh diff --git a/tools/jenkins_scripts/mac/android/build-android-4.x-debug.sh b/tools/jenkins-scripts/mac/android/build-android-4.x-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/build-android-4.x-debug.sh rename to tools/jenkins-scripts/mac/android/build-android-4.x-debug.sh diff --git a/tools/jenkins_scripts/mac/android/build-android-4.x-release.sh b/tools/jenkins-scripts/mac/android/build-android-4.x-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/build-android-4.x-release.sh rename to tools/jenkins-scripts/mac/android/build-android-4.x-release.sh diff --git a/tools/jenkins_scripts/mac/android/generate-js-cxx-bindings.sh b/tools/jenkins-scripts/mac/android/generate-js-cxx-bindings.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/generate-js-cxx-bindings.sh rename to tools/jenkins-scripts/mac/android/generate-js-cxx-bindings.sh diff --git a/tools/jenkins_scripts/mac/android/test-android-2.2-3.2-debug.sh b/tools/jenkins-scripts/mac/android/test-android-2.2-3.2-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/test-android-2.2-3.2-debug.sh rename to tools/jenkins-scripts/mac/android/test-android-2.2-3.2-debug.sh diff --git a/tools/jenkins_scripts/mac/android/test-android-2.2-3.2-release.sh b/tools/jenkins-scripts/mac/android/test-android-2.2-3.2-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/test-android-2.2-3.2-release.sh rename to tools/jenkins-scripts/mac/android/test-android-2.2-3.2-release.sh diff --git a/tools/jenkins_scripts/mac/android/test-android-4.x-debug.sh b/tools/jenkins-scripts/mac/android/test-android-4.x-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/test-android-4.x-debug.sh rename to tools/jenkins-scripts/mac/android/test-android-4.x-debug.sh diff --git a/tools/jenkins_scripts/mac/android/test-android-4.x-release.sh b/tools/jenkins-scripts/mac/android/test-android-4.x-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/android/test-android-4.x-release.sh rename to tools/jenkins-scripts/mac/android/test-android-4.x-release.sh diff --git a/tools/jenkins_scripts/mac/debug.keystore b/tools/jenkins-scripts/mac/debug.keystore similarity index 100% rename from tools/jenkins_scripts/mac/debug.keystore rename to tools/jenkins-scripts/mac/debug.keystore diff --git a/tools/jenkins_scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.html b/tools/jenkins-scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.html similarity index 100% rename from tools/jenkins_scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.html rename to tools/jenkins-scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.html diff --git a/tools/jenkins_scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.py b/tools/jenkins-scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.py similarity index 100% rename from tools/jenkins_scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.py rename to tools/jenkins-scripts/mac/iOS_SikuliTest.sikuli/iOS_SikuliTest.py diff --git a/tools/jenkins_scripts/mac/ios/build-ios-all.sh b/tools/jenkins-scripts/mac/ios/build-ios-all.sh similarity index 100% rename from tools/jenkins_scripts/mac/ios/build-ios-all.sh rename to tools/jenkins-scripts/mac/ios/build-ios-all.sh diff --git a/tools/jenkins_scripts/mac/ios/build-ios-debug.sh b/tools/jenkins-scripts/mac/ios/build-ios-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/ios/build-ios-debug.sh rename to tools/jenkins-scripts/mac/ios/build-ios-debug.sh diff --git a/tools/jenkins_scripts/mac/ios/build-ios-release.sh b/tools/jenkins-scripts/mac/ios/build-ios-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/ios/build-ios-release.sh rename to tools/jenkins-scripts/mac/ios/build-ios-release.sh diff --git a/tools/jenkins_scripts/mac/ios/iphonesim b/tools/jenkins-scripts/mac/ios/iphonesim similarity index 100% rename from tools/jenkins_scripts/mac/ios/iphonesim rename to tools/jenkins-scripts/mac/ios/iphonesim diff --git a/tools/jenkins_scripts/mac/ios/test-ios-debug.sh b/tools/jenkins-scripts/mac/ios/test-ios-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/ios/test-ios-debug.sh rename to tools/jenkins-scripts/mac/ios/test-ios-debug.sh diff --git a/tools/jenkins_scripts/mac/ios/test-ios-release.sh b/tools/jenkins-scripts/mac/ios/test-ios-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/ios/test-ios-release.sh rename to tools/jenkins-scripts/mac/ios/test-ios-release.sh diff --git a/tools/jenkins_scripts/mac/mac/build-mac-all.sh b/tools/jenkins-scripts/mac/mac/build-mac-all.sh similarity index 100% rename from tools/jenkins_scripts/mac/mac/build-mac-all.sh rename to tools/jenkins-scripts/mac/mac/build-mac-all.sh diff --git a/tools/jenkins_scripts/mac/mac/build-mac-debug.sh b/tools/jenkins-scripts/mac/mac/build-mac-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/mac/build-mac-debug.sh rename to tools/jenkins-scripts/mac/mac/build-mac-debug.sh diff --git a/tools/jenkins_scripts/mac/mac/build-mac-release.sh b/tools/jenkins-scripts/mac/mac/build-mac-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/mac/build-mac-release.sh rename to tools/jenkins-scripts/mac/mac/build-mac-release.sh diff --git a/tools/jenkins_scripts/mac/mac/test-mac-debug.sh b/tools/jenkins-scripts/mac/mac/test-mac-debug.sh similarity index 100% rename from tools/jenkins_scripts/mac/mac/test-mac-debug.sh rename to tools/jenkins-scripts/mac/mac/test-mac-debug.sh diff --git a/tools/jenkins_scripts/mac/mac/test-mac-release.sh b/tools/jenkins-scripts/mac/mac/test-mac-release.sh similarity index 100% rename from tools/jenkins_scripts/mac/mac/test-mac-release.sh rename to tools/jenkins-scripts/mac/mac/test-mac-release.sh diff --git a/tools/jenkins_scripts/mac/rootconfig-mac.sh b/tools/jenkins-scripts/mac/rootconfig-mac.sh similarity index 100% rename from tools/jenkins_scripts/mac/rootconfig-mac.sh rename to tools/jenkins-scripts/mac/rootconfig-mac.sh diff --git a/tools/jenkins_scripts/windows/android/androidtestcommon.bat b/tools/jenkins-scripts/windows/android/androidtestcommon.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/androidtestcommon.bat rename to tools/jenkins-scripts/windows/android/androidtestcommon.bat diff --git a/tools/jenkins_scripts/windows/android/build-android-2.2-3.2-debug.bat b/tools/jenkins-scripts/windows/android/build-android-2.2-3.2-debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/build-android-2.2-3.2-debug.bat rename to tools/jenkins-scripts/windows/android/build-android-2.2-3.2-debug.bat diff --git a/tools/jenkins_scripts/windows/android/build-android-2.2-3.2-release.bat b/tools/jenkins-scripts/windows/android/build-android-2.2-3.2-release.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/build-android-2.2-3.2-release.bat rename to tools/jenkins-scripts/windows/android/build-android-2.2-3.2-release.bat diff --git a/tools/jenkins_scripts/windows/android/build-android-4.x-debug.bat b/tools/jenkins-scripts/windows/android/build-android-4.x-debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/build-android-4.x-debug.bat rename to tools/jenkins-scripts/windows/android/build-android-4.x-debug.bat diff --git a/tools/jenkins_scripts/windows/android/build-android-4.x-release.bat b/tools/jenkins-scripts/windows/android/build-android-4.x-release.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/build-android-4.x-release.bat rename to tools/jenkins-scripts/windows/android/build-android-4.x-release.bat diff --git a/tools/jenkins_scripts/windows/android/rootconfig.sh b/tools/jenkins-scripts/windows/android/rootconfig.sh similarity index 100% rename from tools/jenkins_scripts/windows/android/rootconfig.sh rename to tools/jenkins-scripts/windows/android/rootconfig.sh diff --git a/tools/jenkins_scripts/windows/android/test-android-2.2-3.2-debug.bat b/tools/jenkins-scripts/windows/android/test-android-2.2-3.2-debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/test-android-2.2-3.2-debug.bat rename to tools/jenkins-scripts/windows/android/test-android-2.2-3.2-debug.bat diff --git a/tools/jenkins_scripts/windows/android/test-android-2.2-3.2-release.bat b/tools/jenkins-scripts/windows/android/test-android-2.2-3.2-release.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/test-android-2.2-3.2-release.bat rename to tools/jenkins-scripts/windows/android/test-android-2.2-3.2-release.bat diff --git a/tools/jenkins_scripts/windows/android/test-android-4.x-debug.bat b/tools/jenkins-scripts/windows/android/test-android-4.x-debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/test-android-4.x-debug.bat rename to tools/jenkins-scripts/windows/android/test-android-4.x-debug.bat diff --git a/tools/jenkins_scripts/windows/android/test-android-4.x-release.bat b/tools/jenkins-scripts/windows/android/test-android-4.x-release.bat similarity index 100% rename from tools/jenkins_scripts/windows/android/test-android-4.x-release.bat rename to tools/jenkins-scripts/windows/android/test-android-4.x-release.bat diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action0/ObjectRepository.bdb.REMOVED.git-id b/tools/jenkins-scripts/windows/win32/qtp_win32/Action0/ObjectRepository.bdb.REMOVED.git-id similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action0/ObjectRepository.bdb.REMOVED.git-id rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action0/ObjectRepository.bdb.REMOVED.git-id diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action0/Resource.mtr b/tools/jenkins-scripts/windows/win32/qtp_win32/Action0/Resource.mtr similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action0/Resource.mtr rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action0/Resource.mtr diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action0/Script.mts b/tools/jenkins-scripts/windows/win32/qtp_win32/Action0/Script.mts similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action0/Script.mts rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action0/Script.mts diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action1/ObjectRepository.bdb.REMOVED.git-id b/tools/jenkins-scripts/windows/win32/qtp_win32/Action1/ObjectRepository.bdb.REMOVED.git-id similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action1/ObjectRepository.bdb.REMOVED.git-id rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action1/ObjectRepository.bdb.REMOVED.git-id diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action1/Resource.mtr b/tools/jenkins-scripts/windows/win32/qtp_win32/Action1/Resource.mtr similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action1/Resource.mtr rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action1/Resource.mtr diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Action1/Script.mts b/tools/jenkins-scripts/windows/win32/qtp_win32/Action1/Script.mts similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Action1/Script.mts rename to tools/jenkins-scripts/windows/win32/qtp_win32/Action1/Script.mts diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Default.xls b/tools/jenkins-scripts/windows/win32/qtp_win32/Default.xls similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Default.xls rename to tools/jenkins-scripts/windows/win32/qtp_win32/Default.xls diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Error_Sub.vbs b/tools/jenkins-scripts/windows/win32/qtp_win32/Error_Sub.vbs similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Error_Sub.vbs rename to tools/jenkins-scripts/windows/win32/qtp_win32/Error_Sub.vbs diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Error_appcrash.qrs b/tools/jenkins-scripts/windows/win32/qtp_win32/Error_appcrash.qrs similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Error_appcrash.qrs rename to tools/jenkins-scripts/windows/win32/qtp_win32/Error_appcrash.qrs diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Parameters.mtr b/tools/jenkins-scripts/windows/win32/qtp_win32/Parameters.mtr similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Parameters.mtr rename to tools/jenkins-scripts/windows/win32/qtp_win32/Parameters.mtr diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/Test.tsp b/tools/jenkins-scripts/windows/win32/qtp_win32/Test.tsp similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/Test.tsp rename to tools/jenkins-scripts/windows/win32/qtp_win32/Test.tsp diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/TestCpp_Appcrash.tsr.REMOVED.git-id b/tools/jenkins-scripts/windows/win32/qtp_win32/TestCpp_Appcrash.tsr.REMOVED.git-id similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/TestCpp_Appcrash.tsr.REMOVED.git-id rename to tools/jenkins-scripts/windows/win32/qtp_win32/TestCpp_Appcrash.tsr.REMOVED.git-id diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/default.cfg b/tools/jenkins-scripts/windows/win32/qtp_win32/default.cfg similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/default.cfg rename to tools/jenkins-scripts/windows/win32/qtp_win32/default.cfg diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/default.usp b/tools/jenkins-scripts/windows/win32/qtp_win32/default.usp similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/default.usp rename to tools/jenkins-scripts/windows/win32/qtp_win32/default.usp diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/lock.lck b/tools/jenkins-scripts/windows/win32/qtp_win32/lock.lck similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/lock.lck rename to tools/jenkins-scripts/windows/win32/qtp_win32/lock.lck diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/qtp_win32.usr b/tools/jenkins-scripts/windows/win32/qtp_win32/qtp_win32.usr similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/qtp_win32.usr rename to tools/jenkins-scripts/windows/win32/qtp_win32/qtp_win32.usr diff --git a/tools/jenkins_scripts/windows/win32/qtp_win32/qtrunner.vbs b/tools/jenkins-scripts/windows/win32/qtp_win32/qtrunner.vbs similarity index 100% rename from tools/jenkins_scripts/windows/win32/qtp_win32/qtrunner.vbs rename to tools/jenkins-scripts/windows/win32/qtp_win32/qtrunner.vbs diff --git a/tools/jenkins_scripts/windows/win32/test-win-vs2008-debug.bat b/tools/jenkins-scripts/windows/win32/test-win-vs2008-debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/win32/test-win-vs2008-debug.bat rename to tools/jenkins-scripts/windows/win32/test-win-vs2008-debug.bat diff --git a/tools/jenkins_scripts/windows/win32/test-win-vs2008_release.bat b/tools/jenkins-scripts/windows/win32/test-win-vs2008_release.bat similarity index 100% rename from tools/jenkins_scripts/windows/win32/test-win-vs2008_release.bat rename to tools/jenkins-scripts/windows/win32/test-win-vs2008_release.bat diff --git a/tools/jenkins_scripts/windows/win32/test-win-vs2010_debug.bat b/tools/jenkins-scripts/windows/win32/test-win-vs2010_debug.bat similarity index 100% rename from tools/jenkins_scripts/windows/win32/test-win-vs2010_debug.bat rename to tools/jenkins-scripts/windows/win32/test-win-vs2010_debug.bat diff --git a/tools/jenkins_scripts/windows/win32/test-win-vs2010_release.bat b/tools/jenkins-scripts/windows/win32/test-win-vs2010_release.bat similarity index 100% rename from tools/jenkins_scripts/windows/win32/test-win-vs2010_release.bat rename to tools/jenkins-scripts/windows/win32/test-win-vs2010_release.bat diff --git a/tools/project_creator/__init__.py b/tools/project-creator/__init__.py similarity index 100% rename from tools/project_creator/__init__.py rename to tools/project-creator/__init__.py diff --git a/tools/project_creator/create_project.py b/tools/project-creator/create_project.py similarity index 100% rename from tools/project_creator/create_project.py rename to tools/project-creator/create_project.py From 5acbe663e09c0199263bbaa9b0434d4082eb53d0 Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 13:44:57 +0800 Subject: [PATCH 106/116] issue #2905: add missing files --- CODING_STYLE.md | 131 - Emscripten.TODO | 60 - RELEASE_NOTES | 4 - .../bindings/js/debugger/DevToolsUtils.js | 133 + .../javascript/bindings/js/debugger/README.md | 54 + .../bindings/js/debugger/actors/root.js | 329 ++ .../bindings/js/debugger/actors/script.js | 2948 +++++++++++++++++ .../bindings/js/debugger/core/promise.js | 294 ++ .../javascript/bindings/js/debugger/main.js | 928 ++++++ .../bindings/js/debugger/transport.js | 288 ++ 10 files changed, 4974 insertions(+), 195 deletions(-) delete mode 100644 CODING_STYLE.md delete mode 100644 Emscripten.TODO delete mode 100644 RELEASE_NOTES create mode 100644 cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js create mode 100644 cocos/scripting/javascript/bindings/js/debugger/README.md create mode 100644 cocos/scripting/javascript/bindings/js/debugger/actors/root.js create mode 100644 cocos/scripting/javascript/bindings/js/debugger/actors/script.js create mode 100644 cocos/scripting/javascript/bindings/js/debugger/core/promise.js create mode 100644 cocos/scripting/javascript/bindings/js/debugger/main.js create mode 100644 cocos/scripting/javascript/bindings/js/debugger/transport.js diff --git a/CODING_STYLE.md b/CODING_STYLE.md deleted file mode 100644 index 4b7bf2a7c8..0000000000 --- a/CODING_STYLE.md +++ /dev/null @@ -1,131 +0,0 @@ -# cocos2d-x C++ coding sytle - - -## Detailed information - -Please, refer to this document for a detailed version of the cocos2d-x C++ coding sytle: - -* [cocos2d-x c++ coding style](http://www.cocos2d-x.org/wiki/Cocos2d_c++_coding_style) - - -## Quick Sample - -Use this sample as a quick reference. But DO READ the detailed doc for more info. - -Header file: - -```c++ -/** - * We use Doxygen strings for documentation. - * All public classes, methods, structs should be documented using Doxygen Strings - */ -class CC_DLL Sprite : public NodeRGBA, public TextureProtocol -{ /* class braces start in a new line */ - -/* no indentation here for public, protected or private */ -/* First add all the "public" stuff, then all the "protected" stuff, and finally all the "private" stuff -public: - - /* we don't use tabs, we use spaces, and we use a 4 space identation */ - /* 1st add all static const */ - static const int INDEX_NOT_INITIALIZED = -1; - - /* then add all the creators and other relevant static methods */ - static Sprite* create(); - static Sprite* create(const char *filename); - static Sprite* create(const char *filename, const Rect& rect); - - /* if applicable, then add the consturctors / destructors */ - Sprite(); - virtual ~Sprite(void); - - /* then add all the initialization methods */ - /* notice that they are in the same order as the creators */ - virtual bool init(void); - virtual bool initWithTexture(Texture2D *texture); - virtual bool initWithTexture(Texture2D *texture, const Rect& rect); - - - - /* then add the regular instace methods */ - virtual void updateTransform(void); - virtual SpriteBatchNode* getBatchNode(void); - virtual void setBatchNode(SpriteBatchNode *spriteBatchNode); - - - /* then add all the overriden methods */ - /* notice that all overriden methods must use the 'override' keyword */ - /* overriden methods are not forced to have doxygen strings UNLESS they change the behavior in a non obvios way */ - virtual void setPosition(const Point& pos) override; - virtual void setRotation(float rotation) override; - virtual void setRotationX(float rotationX) override; - - - /* once you finish with the 'public' methods, start with the 'protected' ones */ -protected: - - /* protected methods are not forced to have Doxygen strings, but if they have it, better */ - void updateColor(void); - virtual void setTextureCoords(Rect rect); - - /* After adding all the methods, add the ivars */ - /* all ivars must start with _ */ - /* Do not use Hungarian notation */ - TextureAtlas* _textureAtlas; - int _atlasIndex; - SpriteBatchNode* _batchNode; -}; - -``` - -Implementation file: - -```c++ -/* Do not use doxygen comments on the implementation file */ - -/* The methos MUST be in the same order as where declared in the header file */ - -Sprite* Sprite::create(const char *filename) -{ - /* Don't use tabs. Use spaces. Use 4-space indentation */ - Sprite *sprite = new Sprite(); - - /* put curly braces in the same line as in the 'if'*/ - /* leave a space between the 'if' and the '(' */ - /* don't leave spaces between '()' */ - if (sprite && sprite->initWithFile(filename)) { - sprite->autorelease(); - return sprite; - } - CC_SAFE_DELETE(sprite); - return NULL; -} - -/* Initialization list can be indented to 0 spaces, or to 4 spaces. If in doubt, be consistent with the indentation already used in the file */ -/* Only use the Initialization lists for types that can't fail when initialized */ -Sprite::Sprite() -: _shouldBeHidden(false) -, _texture(nullptr) -, _physicsBody(nullptr) -{ -} - -/* use the 'initXXX' methods to initialize types that might fail */ -bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) -{ - /* it ok not use use curly braces */ - if (something) - do_something(); - else - something_else(); - - /* but if you use curly branches in one branch, all the branches should use curly branches */ - if (something) { - do_something1(); - do_something2(); - } else { - so_something_else(); - } -} - -``` diff --git a/Emscripten.TODO b/Emscripten.TODO deleted file mode 100644 index a00ca3ce9e..0000000000 --- a/Emscripten.TODO +++ /dev/null @@ -1,60 +0,0 @@ -* Need to figure out how to get correct screen resolutions consistently. - -* Touch handler screwed up after TouchesTest? MenuTest? (TestCpp sample) - -* TTF Font rendering is slow and seems to wrap around by a few pixels - horizontally. Need to investigate here, but I suspect the right answer is to - offload font rendering to an offscreen canvas and let the browser handle it. - Potentially creates new challenges in packaging which would need to be solved - somehow. - - - -### -DONE: -### - -* Need to switch to server-side buffers in -- cocos2dx/draw_nodes/CCDrawingPrimitives - -* Need to compile with -O2 -- possible -s VERBOSE=1 will give a clue? - -* SchedulerTest crashes - - cocos2d::CCNode::boundingBox() - -* Parallax Test crashes - - cocos2d::CCAtlasNode::calculateMaxItems() - -* Particle Test crashes - - TIFFClientOpen not a function. Looks like we need to build and link in libtiff. - -* cocos2d::CCAtlasNode::calculateMaxItems() throwing an error; related to - CCTextureAtlas? Preventing particle test from working. - -* Need to switch to server-side buffers in -- cocos2dx/draw_nodes/CCDrawNode.cpp -- Think this is fixed by undef CC_TEXTURE_ATLAS_USE_VAO? -- cocos2dx/particle_nodes/CCParticleSystemQuad.cpp -- Think this is fixed by CC_REBIND_INDICES_BUFFER? -- cocos2dx/textures/CCTextureAtlas.cpp -- Think this works already. - -* Layer Test crashes - - cocos2d::CCLabelBMFont::create(char const*, char const*, float, cocos2d::CCTextAlignment, cocos2d::CCPoint) - -* IntervalTest crashes - - cocos2d::CCLabelBMFont::create(char const*, char const*, float, cocos2d::CCTextAlignment, cocos2d::CCPoint) - -* TileMap Test crashes - - void CCNode::insertChild(CCNode* child, int z) - -* LabelTest crashes - - cocos2d::CCAtlasNode::calculateMaxItems() - -* ZwoptexTest crashes. - - ZwoptexGenericTest::onEnter() - -* ChipmunkTest crashes: - Aborting due to Chipmunk error: Moment of Inertia must be positive and non-zero. - Failed condition: moment > 0.0f - Source:../src/cpBody.c:151 - -* Add linkage to libjpeg to get RenderTexture test to work. - diff --git a/RELEASE_NOTES b/RELEASE_NOTES deleted file mode 100644 index f10872da6c..0000000000 --- a/RELEASE_NOTES +++ /dev/null @@ -1,4 +0,0 @@ -===== cocos2d-x 3.0 Release Notes ===== - -Please, read the online release notes document: -http://www.cocos2d-x.org/wiki/Release_Notes_for_Cocos2d-x_v300 \ No newline at end of file diff --git a/cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js b/cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js new file mode 100644 index 0000000000..26d0597644 --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js @@ -0,0 +1,133 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +function utf16to8(str) { + var out, i, len, c; + + out = ""; + len = str.length; + for(i = 0; i < len; i++) + { + c = str.charCodeAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) + { + out += str.charAt(i); + } + else if (c > 0x07FF) + { + out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); + out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } + else + { + out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } + } + return out; +} + +function utf8to16(str) { + var out, i, len, c; + var char2, char3; + + out = ""; + len = str.length; + i = 0; + while(i < len) { c = str.charCodeAt(i++); switch(c >> 4) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + // 0xxxxxxx + out += str.charAt(i-1); + break; + case 12: case 13: + // 110x xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + char3 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + break; + } + } + + return out; + } + +var dump = function(msg) { + log(msg); +}; + +/* General utilities used throughout devtools. */ + +/* Turn the error e into a string, without fail. */ +this.safeErrorString = function safeErrorString(aError) { + try { + var s = aError.toString(); + if (typeof s === "string") + return s; + } catch (ee) { } + + return ""; +} + +/** + * Report that |aWho| threw an exception, |aException|. + */ +this.reportException = function reportException(aWho, aException) { + let msg = aWho + " threw an exception: " + safeErrorString(aException); + if (aException.stack) { + msg += "\nCall stack:\n" + aException.stack; + } + + dump(msg + "\n"); + + // if (Components.utils.reportError) { + // /* + // * Note that the xpcshell test harness registers an observer for + // * console messages, so when we're running tests, this will cause + // * the test to quit. + // */ + // Components.utils.reportError(msg); + // } +} + +/** + * Given a handler function that may throw, return an infallible handler + * function that calls the fallible handler, and logs any exceptions it + * throws. + * + * @param aHandler function + * A handler function, which may throw. + * @param aName string + * A name for aHandler, for use in error messages. If omitted, we use + * aHandler.name. + * + * (SpiderMonkey does generate good names for anonymous functions, but we + * don't have a way to get at them from JavaScript at the moment.) + */ +this.makeInfallible = function makeInfallible(aHandler, aName) { + if (!aName) + aName = aHandler.name; + + return function (/* arguments */) { + try { + return aHandler.apply(this, arguments); + } catch (ex) { + let who = "Handler function"; + if (aName) { + who += " " + aName; + } + reportException(who, ex); + } + } +} diff --git a/cocos/scripting/javascript/bindings/js/debugger/README.md b/cocos/scripting/javascript/bindings/js/debugger/README.md new file mode 100644 index 0000000000..9e1d7bebd0 --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/README.md @@ -0,0 +1,54 @@ +Remote Debugging By Using FireFox +================================= + +Requirement +----------- + +* Firefox: From v24 + +How To Use +---------- + +### Prepare ### + +Please refer to https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging . + +### Enable Debugger Support For Your JSB Project ### + +``` +bool AppDelegate::applicationDidFinishLaunching() +{ + ... + + ScriptingCore* sc = ScriptingCore::getInstance(); + sc->addRegisterCallback(register_all_cocos2dx); + sc->addRegisterCallback(register_all_cocos2dx_extension); + sc->addRegisterCallback(register_cocos2dx_js_extensions); + sc->addRegisterCallback(jsb_register_chipmunk); + sc->addRegisterCallback(register_all_cocos2dx_extension_manual); + sc->addRegisterCallback(register_CCBuilderReader); + sc->addRegisterCallback(jsb_register_system); + sc->addRegisterCallback(JSB_register_opengl); + + sc->start(); + +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + sc->enableDebugger(); // Enable debugger here +#endif + + ... +} +``` + +Run your game. + +### Open Firefox And Follow The Step As Follows ### + + +![pic 1](https://lh5.googleusercontent.com/-HoxLGBdV2J0/UlZ7ZoFUjyI/AAAAAAAAADM/68GDaCQ1vP0/s0-I/Firefox-Remote-Debug01.jpg) +![pic 2](https://lh6.googleusercontent.com/-7FDIHAYsKAY/UlZ7Yf8W-pI/AAAAAAAAAFQ/joG0AymnuBk/s0-I/Firefox-Remote-Debug02.jpg) +![pic 3](https://lh4.googleusercontent.com/-idvnMRGcGy8/UlZ7Wj6DDuI/AAAAAAAAAC0/L9IVyHLNqeQ/s0-I/Firefox-Remote-Debug04.jpg) +![pic 4](https://lh6.googleusercontent.com/-YuZj7JGAtFE/UlZ9DDGDczI/AAAAAAAAAEQ/D2qIedjP5FU/s0-I/Firefox-Remote-Debug04.png.png) +![pic 5](https://lh3.googleusercontent.com/-cdIcNa3jT5c/UlZ9uapf3OI/AAAAAAAAAEg/MGq3vLHsauw/s0-I/Firefox-Remote-Debug05.png) +![pic 6](https://lh5.googleusercontent.com/-T79-o5ylJKI/UlZ_JJQe3MI/AAAAAAAAAE8/F63fSVxlJKs/s0-I/Firefox-Remote-Debug06.png) + diff --git a/cocos/scripting/javascript/bindings/js/debugger/actors/root.js b/cocos/scripting/javascript/bindings/js/debugger/actors/root.js new file mode 100644 index 0000000000..aa0d85342b --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/actors/root.js @@ -0,0 +1,329 @@ +/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/* Root actor for the remote debugging protocol. */ + +/** + * Methods shared between RootActor and BrowserTabActor. + */ + +/** + * Populate |this._extraActors| as specified by |aFactories|, reusing whatever + * actors are already there. Add all actors in the final extra actors table to + * |aPool|. + * + * The root actor and the tab actor use this to instantiate actors that other + * parts of the browser have specified with DebuggerServer.addTabActor antd + * DebuggerServer.addGlobalActor. + * + * @param aFactories + * An object whose own property names are the names of properties to add to + * some reply packet (say, a tab actor grip or the "listTabs" response + * form), and whose own property values are actor constructor functions, as + * documented for addTabActor and addGlobalActor. + * + * @param this + * The BrowserRootActor or BrowserTabActor with which the new actors will + * be associated. It should support whatever API the |aFactories| + * constructor functions might be interested in, as it is passed to them. + * For the sake of CommonCreateExtraActors itself, it should have at least + * the following properties: + * + * - _extraActors + * An object whose own property names are factory table (and packet) + * property names, and whose values are no-argument actor constructors, + * of the sort that one can add to an ActorPool. + * + * - conn + * The DebuggerServerConnection in which the new actors will participate. + * + * - actorID + * The actor's name, for use as the new actors' parentID. + */ +function CommonCreateExtraActors(aFactories, aPool) { + // Walk over global actors added by extensions. + for (let name in aFactories) { + let actor = this._extraActors[name]; + if (!actor) { + actor = aFactories[name].bind(null, this.conn, this); + actor.prototype = aFactories[name].prototype; + actor.parentID = this.actorID; + this._extraActors[name] = actor; + } + aPool.addActor(actor); + } +} + +/** + * Append the extra actors in |this._extraActors|, constructed by a prior call + * to CommonCreateExtraActors, to |aObject|. + * + * @param aObject + * The object to which the extra actors should be added, under the + * property names given in the |aFactories| table passed to + * CommonCreateExtraActors. + * + * @param this + * The BrowserRootActor or BrowserTabActor whose |_extraActors| table we + * should use; see above. + */ +function CommonAppendExtraActors(aObject) { + for (let name in this._extraActors) { + let actor = this._extraActors[name]; + aObject[name] = actor.actorID; + } +} + +/** + * Create a remote debugging protocol root actor. + * + * @param aConnection + * The DebuggerServerConnection whose root actor we are constructing. + * + * @param aParameters + * The properties of |aParameters| provide backing objects for the root + * actor's requests; if a given property is omitted from |aParameters|, the + * root actor won't implement the corresponding requests or notifications. + * Supported properties: + * + * - tabList: a live list (see below) of tab actors. If present, the + * new root actor supports the 'listTabs' request, providing the live + * list's elements as its tab actors, and sending 'tabListChanged' + * notifications when the live list's contents change. One actor in + * this list must have a true '.selected' property. + * + * - globalActorFactories: an object |A| describing further actors to + * attach to the 'listTabs' reply. This is the type accumulated by + * DebuggerServer.addGlobalActor. For each own property |P| of |A|, + * the root actor adds a property named |P| to the 'listTabs' + * reply whose value is the name of an actor constructed by + * |A[P]|. + * + * - onShutdown: a function to call when the root actor is disconnected. + * + * Instance properties: + * + * - applicationType: the string the root actor will include as the + * "applicationType" property in the greeting packet. By default, this + * is "browser". + * + * Live lists: + * + * A "live list", as used for the |tabList|, is an object that presents a + * list of actors, and also notifies its clients of changes to the list. A + * live list's interface is two properties: + * + * - iterator: a method that returns an iterator. A for-of loop will call + * this method to obtain an iterator for the loop, so if LL is + * a live list, one can simply write 'for (i of LL) ...'. + * + * - onListChanged: a handler called, with no arguments, when the set of + * values the iterator would produce has changed since the last + * time 'iterator' was called. This may only be set to null or a + * callable value (one for which the typeof operator returns + * 'function'). (Note that the live list will not call the + * onListChanged handler until the list has been iterated over + * once; if nobody's seen the list in the first place, nobody + * should care if its contents have changed!) + * + * When the list changes, the list implementation should ensure that any + * actors yielded in previous iterations whose referents (tabs) still exist + * get yielded again in subsequent iterations. If the underlying referent + * is the same, the same actor should be presented for it. + * + * The root actor registers an 'onListChanged' handler on the appropriate + * list when it may need to send the client 'tabListChanged' notifications, + * and is careful to remove the handler whenever it does not need to send + * such notifications (including when it is disconnected). This means that + * live list implementations can use the state of the handler property (set + * or null) to install and remove observers and event listeners. + * + * Note that, as the only way for the root actor to see the members of the + * live list is to begin an iteration over the list, the live list need not + * actually produce any actors until they are reached in the course of + * iteration: alliterative lazy live lists. + */ +function RootActor(aConnection, aParameters) { + this.conn = aConnection; + this._parameters = aParameters; + this._onTabListChanged = this.onTabListChanged.bind(this); + this._extraActors = {}; +} + +RootActor.prototype = { + constructor: RootActor, + applicationType: "browser", + + /** + * Return a 'hello' packet as specified by the Remote Debugging Protocol. + */ + sayHello: function() { + return { + from: "root", + applicationType: this.applicationType, + /* This is not in the spec, but it's used by tests. */ + testConnectionPrefix: this.conn.prefix, + traits: { + sources: true + } + }; + }, + + /** + * Disconnects the actor from the browser window. + */ + disconnect: function() { + /* Tell the live lists we aren't watching any more. */ + if (this._parameters.tabList) { + this._parameters.tabList.onListChanged = null; + } + if (typeof this._parameters.onShutdown === 'function') { + this._parameters.onShutdown(); + } + this._extraActors = null; + }, + + /* The 'listTabs' request and the 'tabListChanged' notification. */ + + /** + * Handles the listTabs request. The actors will survive until at least + * the next listTabs request. + */ + onListTabs: function() { + + let tabList = this._parameters.tabList; + if (!tabList) { + return { from: "root", error: "noTabs", + message: "This root actor has no browser tabs." }; + } + + /* + * Walk the tab list, accumulating the array of tab actors for the + * reply, and moving all the actors to a new ActorPool. We'll + * replace the old tab actor pool with the one we build here, thus + * retiring any actors that didn't get listed again, and preparing any + * new actors to receive packets. + */ + let newActorPool = new ActorPool(this.conn); + let tabActorList = []; + let selected; + for (let tabActor of tabList) { + if (tabActor.selected) { + selected = tabActorList.length; + } + tabActor.parentID = this.actorID; + newActorPool.addActor(tabActor); + tabActorList.push(tabActor); + } + + /* DebuggerServer.addGlobalActor support: create actors. */ + this._createExtraActors(this._parameters.globalActorFactories, newActorPool); + + /* + * Drop the old actorID -> actor map. Actors that still mattered were + * added to the new map; others will go away. + */ + if (this._tabActorPool) { + this.conn.removeActorPool(this._tabActorPool); + } + this._tabActorPool = newActorPool; + this.conn.addActorPool(this._tabActorPool); + + let reply = { + "from": "root", + "selected": selected || 0, + "tabs": [actor.grip() for (actor of tabActorList)] + }; + + /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */ + this._appendExtraActors(reply); + + /* + * Now that we're actually going to report the contents of tabList to + * the client, we're responsible for letting the client know if it + * changes. + */ + tabList.onListChanged = this._onTabListChanged; + + return reply; + }, + + onTabListChanged: function () { + this.conn.send({ from:"root", type:"tabListChanged" }); + /* It's a one-shot notification; no need to watch any more. */ + this._parameters.tabList.onListChanged = null; + }, + + /* This is not in the spec, but it's used by tests. */ + onEcho: (aRequest) => aRequest, + + /* Support for DebuggerServer.addGlobalActor. */ + _createExtraActors: CommonCreateExtraActors, + _appendExtraActors: CommonAppendExtraActors, + + /* ThreadActor hooks. */ + + /** + * Prepare to enter a nested event loop by disabling debuggee events. + */ + preNest: function() { + // Disable events in all open windows. + let e = windowMediator.getEnumerator(null); + while (e.hasMoreElements()) { + let win = e.getNext(); + let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.suppressEventHandling(true); + windowUtils.suspendTimeouts(); + } + }, + + /** + * Prepare to exit a nested event loop by enabling debuggee events. + */ + postNest: function(aNestData) { + // Enable events in all open windows. + let e = windowMediator.getEnumerator(null); + while (e.hasMoreElements()) { + let win = e.getNext(); + let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.resumeTimeouts(); + windowUtils.suppressEventHandling(false); + } + }, + + /* ChromeDebuggerActor hooks. */ + + /** + * Add the specified actor to the default actor pool connection, in order to + * keep it alive as long as the server is. This is used by breakpoints in the + * thread and chrome debugger actors. + * + * @param actor aActor + * The actor object. + */ + addToParentPool: function(aActor) { + this.conn.addActor(aActor); + }, + + /** + * Remove the specified actor from the default actor pool. + * + * @param BreakpointActor aActor + * The actor object. + */ + removeFromParentPool: function(aActor) { + this.conn.removeActor(aActor); + } +} + +RootActor.prototype.requestTypes = { + "listTabs": RootActor.prototype.onListTabs, + "echo": RootActor.prototype.onEcho +}; diff --git a/cocos/scripting/javascript/bindings/js/debugger/actors/script.js b/cocos/scripting/javascript/bindings/js/debugger/actors/script.js new file mode 100644 index 0000000000..7ddade2b54 --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/actors/script.js @@ -0,0 +1,2948 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; js-indent-level: 2; -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * JSD2 actors. + */ +/** + * Creates a ThreadActor. + * + * ThreadActors manage a JSInspector object and manage execution/inspection + * of debuggees. + * + * @param aHooks object + * An object with preNest and postNest methods for calling when entering + * and exiting a nested event loop, addToParentPool and + * removeFromParentPool methods for handling the lifetime of actors that + * will outlive the thread, like breakpoints. + * @param aGlobal object [optional] + * An optional (for content debugging only) reference to the content + * window. + */ +function ThreadActor(aHooks, aGlobal) +{ + this._state = "detached"; + this._frameActors = []; + this._environmentActors = []; + this._hooks = aHooks; + this.global = aGlobal; + + this.findGlobals = this.globalManager.findGlobals.bind(this); + this.onNewGlobal = this.globalManager.onNewGlobal.bind(this); + this.onNewSource = this.onNewSource.bind(this); + + this._options = { + useSourceMaps: false + }; +} + +/** + * The breakpoint store must be shared across instances of ThreadActor so that + * page reloads don't blow away all of our breakpoints. + */ +ThreadActor._breakpointStore = {}; + +ThreadActor.prototype = { + actorPrefix: "context", + + get state() { return this._state; }, + get attached() this.state == "attached" || + this.state == "running" || + this.state == "paused", + + get _breakpointStore() { return ThreadActor._breakpointStore; }, + + get threadLifetimePool() { + if (!this._threadLifetimePool) { + this._threadLifetimePool = new ActorPool(this.conn); + this.conn.addActorPool(this._threadLifetimePool); + this._threadLifetimePool.objectActors = new WeakMap(); + } + return this._threadLifetimePool; + }, + + get sources() { + if (!this._sources) { + this._sources = new ThreadSources(this, this._options.useSourceMaps, + this._allowSource, this.onNewSource); + } + return this._sources; + }, + + clearDebuggees: function TA_clearDebuggees() { + if (this.dbg) { + this.dbg.removeAllDebuggees(); + } + this.conn.removeActorPool(this._threadLifetimePool || undefined); + this._threadLifetimePool = null; + this._sources = null; + }, + + /** + * Add a debuggee global to the Debugger object. + */ + addDebuggee: function TA_addDebuggee(aGlobal) { + try { + this.dbg.addDebuggee(aGlobal); + } catch (e) { + // Ignore attempts to add the debugger's compartment as a debuggee. + dumpn("Ignoring request to add the debugger's compartment as a debuggee"); + } + }, + + /** + * Initialize the Debugger. + */ + _initDebugger: function TA__initDebugger() { + this.dbg = new Debugger(); + this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this); + this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this); + this.dbg.onNewScript = this.onNewScript.bind(this); + this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this); + // Keep the debugger disabled until a client attaches. + this.dbg.enabled = this._state != "detached"; + }, + + /** + * Remove a debuggee global from the JSInspector. + */ + removeDebugee: function TA_removeDebuggee(aGlobal) { + try { + this.dbg.removeDebuggee(aGlobal); + } catch(ex) { + // XXX: This debuggee has code currently executing on the stack, + // we need to save this for later. + } + }, + + /** + * Add the provided window and all windows in its frame tree as debuggees. + */ + _addDebuggees: function TA__addDebuggees(aWindow) { + this.addDebuggee(aWindow); + let frames = aWindow.frames; + if (frames) { + for (let i = 0; i < frames.length; i++) { + this._addDebuggees(frames[i]); + } + } + }, + + /** + * An object that will be used by ThreadActors to tailor their behavior + * depending on the debugging context being required (chrome or content). + */ + globalManager: { + findGlobals: function TA_findGlobals() { + this._addDebuggees(this.global); + }, + + /** + * A function that the engine calls when a new global object has been + * created. + * + * @param aGlobal Debugger.Object + * The new global object that was created. + */ + onNewGlobal: function TA_onNewGlobal(aGlobal) { + // Content debugging only cares about new globals in the contant window, + // like iframe children. + if (aGlobal.hostAnnotations && + aGlobal.hostAnnotations.type == "document" && + aGlobal.hostAnnotations.element === this.global) { + this.addDebuggee(aGlobal); + // Notify the client. + this.conn.send({ + from: this.actorID, + type: "newGlobal", + // TODO: after bug 801084 lands see if we need to JSONify this. + hostAnnotations: aGlobal.hostAnnotations + }); + } + } + }, + + disconnect: function TA_disconnect() { + dumpn("in ThreadActor.prototype.disconnect"); + if (this._state == "paused") { + this.onResume(); + } + + this._state = "exited"; + + this.clearDebuggees(); + + if (!this.dbg) { + return; + } + this.dbg.enabled = false; + this.dbg = null; + }, + + /** + * Disconnect the debugger and put the actor in the exited state. + */ + exit: function TA_exit() { + this.disconnect(); + }, + + // Request handlers + onAttach: function TA_onAttach(aRequest) { + if (this.state === "exited") { + return { type: "exited" }; + } + + if (this.state !== "detached") { + return { error: "wrongState" }; + } + + this._state = "attached"; + + update(this._options, aRequest.options || {}); + + if (!this.dbg) { + this._initDebugger(); + } + this.findGlobals(); + this.dbg.enabled = true; + try { + // Put ourselves in the paused state. + let packet = this._paused(); + if (!packet) { + return { error: "notAttached" }; + } + packet.why = { type: "attached" }; + + this._restoreBreakpoints(); + + // Send the response to the attach request now (rather than + // returning it), because we're going to start a nested event loop + // here. + this.conn.send(packet); + + // Start a nested event loop. + this._nest(); + + // We already sent a response to this request, don't send one + // now. + return null; + } catch (e) { + reportError(e); + return { error: "notAttached", message: e.toString() }; + } + }, + + onDetach: function TA_onDetach(aRequest) { + this.disconnect(); + dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet"); + return { + type: "detached" + }; + }, + + onReconfigure: function TA_onReconfigure(aRequest) { + if (this.state == "exited") { + return { error: "wrongState" }; + } + + update(this._options, aRequest.options || {}); + // Clear existing sources, so they can be recreated on next access. + this._sources = null; + + return {}; + }, + + /** + * Pause the debuggee, by entering a nested event loop, and return a 'paused' + * packet to the client. + * + * @param Debugger.Frame aFrame + * The newest debuggee frame in the stack. + * @param object aReason + * An object with a 'type' property containing the reason for the pause. + * @param function onPacket + * Hook to modify the packet before it is sent. Feel free to return a + * promise. + */ + _pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason, + onPacket=function (k) k) { + try { + let packet = this._paused(aFrame); + if (!packet) { + return undefined; + } + packet.why = aReason; + resolve(onPacket(packet)).then(this.conn.send.bind(this.conn)); + return this._nest(); + } catch(e) { + let msg = "Got an exception during TA__pauseAndRespond: " + e + + ": " + e.stack; + // Cu.reportError(msg); + dumpn(msg); + return undefined; + } + }, + + /** + * Handle a protocol request to resume execution of the debuggee. + */ + onResume: function TA_onResume(aRequest) { + if (this._state !== "paused") { + return { + error: "wrongState", + message: "Can't resume when debuggee isn't paused. Current state is '" + + this._state + "'" + }; + } + + // In case of multiple nested event loops (due to multiple debuggers open in + // different tabs or multiple debugger clients connected to the same tab) + // only allow resumption in a LIFO order. + if (DebuggerServer.xpcInspector.eventLoopNestLevel() > 1) { + log("DebuggerServer.xpcInspector.eventLoopNestLevel: "+DebuggerServer.xpcInspector.eventLoopNestLevel()); + // let lastNestRequestor = DebuggerServer.xpcInspector.lastNestRequestor; + // if (lastNestRequestor.connection != this.conn) { + // return { error: "wrongOrder", + // message: "trying to resume in the wrong order.", + // lastPausedUrl: lastNestRequestor.url }; + // } + } + + if (aRequest && aRequest.forceCompletion) { + // TODO: remove this when Debugger.Frame.prototype.pop is implemented in + // bug 736733. + if (typeof this.frame.pop != "function") { + return { error: "notImplemented", + message: "forced completion is not yet implemented." }; + } + + this.dbg.getNewestFrame().pop(aRequest.completionValue); + let packet = this._resumed(); + DebuggerServer.xpcInspector.exitNestedEventLoop(); + return { type: "resumeLimit", frameFinished: aRequest.forceCompletion }; + } + + if (aRequest && aRequest.resumeLimit) { + log("resumeLimit..."); + // Bind these methods because some of the hooks are called with 'this' + // set to the current frame. + let pauseAndRespond = (aFrame, onPacket=function (k) k) => { + this._pauseAndRespond(aFrame, { type: "resumeLimit" }, onPacket); + }; + let createValueGrip = this.createValueGrip.bind(this); + + let startFrame = this.youngestFrame; + let startLine; + if (this.youngestFrame.script) { + let offset = this.youngestFrame.offset; + startLine = this.youngestFrame.script.getOffsetLine(offset); + } + + // Define the JS hook functions for stepping. + + let onEnterFrame = aFrame => { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + return pauseAndRespond(aFrame); + }; + + let thread = this; + + let onPop = function TA_onPop(aCompletion) { + // onPop is called with 'this' set to the current frame. + if (thread.sources.isBlackBoxed(this.script.url)) { + return undefined; + } + + // Note that we're popping this frame; we need to watch for + // subsequent step events on its caller. + this.reportedPop = true; + + return pauseAndRespond(this, (aPacket) => { + aPacket.why.frameFinished = {}; + if (!aCompletion) { + aPacket.why.frameFinished.terminated = true; + } else if (aCompletion.hasOwnProperty("return")) { + aPacket.why.frameFinished.return = createValueGrip(aCompletion.return); + } else if (aCompletion.hasOwnProperty("yield")) { + aPacket.why.frameFinished.return = createValueGrip(aCompletion.yield); + } else { + aPacket.why.frameFinished.throw = createValueGrip(aCompletion.throw); + } + return aPacket; + }); + }; + + let onStep = function TA_onStep() { + // onStep is called with 'this' set to the current frame. + + if (thread.sources.isBlackBoxed(this.script.url)) { + return undefined; + } + + // If we've changed frame or line, then report that. + if (this !== startFrame || + (this.script && + this.script.getOffsetLine(this.offset) != startLine)) { + return pauseAndRespond(this); + } + + // Otherwise, let execution continue. + return undefined; + }; + + let steppingType = aRequest.resumeLimit.type; + if (["step", "next", "finish"].indexOf(steppingType) == -1) { + return { error: "badParameterType", + message: "Unknown resumeLimit type" }; + } + // Make sure there is still a frame on the stack if we are to continue + // stepping. + let stepFrame = this._getNextStepFrame(startFrame); + if (stepFrame) { + switch (steppingType) { + case "step": + log("--> step..."); + this.dbg.onEnterFrame = onEnterFrame; + // Fall through. + case "next": + log("--> next..."); + stepFrame.onStep = onStep; + stepFrame.onPop = onPop; + break; + case "finish": + log("--> finish..."); + stepFrame.onPop = onPop; + } + } + + } + + if (aRequest && aRequest.pauseOnExceptions) { + this.dbg.onExceptionUnwind = this.onExceptionUnwind.bind(this); + } + let packet = this._resumed(); + DebuggerServer.xpcInspector.exitNestedEventLoop(); + return packet; + }, + + /** + * Helper method that returns the next frame when stepping. + */ + _getNextStepFrame: function TA__getNextStepFrame(aFrame) { + let stepFrame = aFrame.reportedPop ? aFrame.older : aFrame; + if (!stepFrame || !stepFrame.script) { + stepFrame = null; + } + return stepFrame; + }, + + onClientEvaluate: function TA_onClientEvaluate(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Debuggee must be paused to evaluate code." }; + }; + + let frame = this._requestFrame(aRequest.frame); + if (!frame) { + return { error: "unknownFrame", + message: "Evaluation frame not found" }; + } + + if (!frame.environment) { + return { error: "notDebuggee", + message: "cannot access the environment of this frame." }; + }; + + // We'll clobber the youngest frame if the eval causes a pause, so + // save our frame now to be restored after eval returns. + // XXX: or we could just start using dbg.getNewestFrame() now that it + // works as expected. + let youngest = this.youngestFrame; + + // Put ourselves back in the running state and inform the client. + let resumedPacket = this._resumed(); + this.conn.send(resumedPacket); + + // Run the expression. + // XXX: test syntax errors + let completion = frame.eval(aRequest.expression); + + // Put ourselves back in the pause state. + let packet = this._paused(youngest); + packet.why = { type: "clientEvaluated", + frameFinished: this.createProtocolCompletionValue(completion) }; + + // Return back to our previous pause's event loop. + return packet; + }, + + onFrames: function TA_onFrames(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Stack frames are only available while the debuggee is paused."}; + } + + let start = aRequest.start ? aRequest.start : 0; + let count = aRequest.count; + + // Find the starting frame... + let frame = this.youngestFrame; + let i = 0; + while (frame && (i < start)) { + frame = frame.older; + i++; + } + + // Return request.count frames, or all remaining + // frames if count is not defined. + let frames = []; + let promises = []; + for (; frame && (!count || i < (start + count)); i++, frame=frame.older) { + let form = this._createFrameActor(frame).form(); + form.depth = i; + frames.push(form); + + let promise = this.sources.getOriginalLocation(form.where.url, + form.where.line) + .then(function (aOrigLocation) { + form.where = aOrigLocation; + }); + promises.push(promise); + } + + return all(promises).then(function () { + return { frames: frames }; + }); + }, + + onReleaseMany: function TA_onReleaseMany(aRequest) { + if (!aRequest.actors) { + return { error: "missingParameter", + message: "no actors were specified" }; + } + + let res; + for each (let actorID in aRequest.actors) { + let actor = this.threadLifetimePool.get(actorID); + if (!actor) { + if (!res) { + res = { error: "notReleasable", + message: "Only thread-lifetime actors can be released." }; + } + continue; + } + actor.onRelease(); + } + return res ? res : {}; + }, + + /** + * Handle a protocol request to set a breakpoint. + */ + onSetBreakpoint: function TA_onSetBreakpoint(aRequest) { + if (this.state !== "paused") { + return { error: "wrongState", + message: "Breakpoints can only be set while the debuggee is paused."}; + } + + // XXX: `originalColumn` is never used. See bug 827639. + let { url: originalSource, + line: originalLine, + column: originalColumn } = aRequest.location; + + let locationPromise = this.sources.getGeneratedLocation(originalSource, + originalLine) + return locationPromise.then((aLocation) => { + let line = aLocation.line; + if (this.dbg.findScripts({ url: aLocation.url }).length == 0 || + line < 0 || + line == null) { + return { error: "noScript" }; + } + + // Add the breakpoint to the store for later reuse, in case it belongs to a + // script that hasn't appeared yet. + if (!this._breakpointStore[aLocation.url]) { + this._breakpointStore[aLocation.url] = []; + } + let scriptBreakpoints = this._breakpointStore[aLocation.url]; + scriptBreakpoints[line] = { + url: aLocation.url, + line: line, + column: aLocation.column + }; + + let response = this._setBreakpoint(aLocation); + // If the original location of our generated location is different from + // the original location we attempted to set the breakpoint on, we will + // need to know so that we can set actualLocation on the response. + let originalLocation = this.sources.getOriginalLocation(aLocation.url, + aLocation.line); + + return all([response, originalLocation]) + .then(([aResponse, {url, line}]) => { + if (aResponse.actualLocation) { + let actualOrigLocation = this.sources.getOriginalLocation( + aResponse.actualLocation.url, aResponse.actualLocation.line); + return actualOrigLocation.then(function ({ url, line }) { + if (url !== originalSource || line !== originalLine) { + aResponse.actualLocation = { url: url, line: line }; + } + return aResponse; + }); + } + + if (url !== originalSource || line !== originalLine) { + aResponse.actualLocation = { url: url, line: line }; + } + + return aResponse; + }); + }); + }, + + /** + * Set a breakpoint using the jsdbg2 API. If the line on which the breakpoint + * is being set contains no code, then the breakpoint will slide down to the + * next line that has runnable code. In this case the server breakpoint cache + * will be updated, so callers that iterate over the breakpoint cache should + * take that into account. + * + * @param object aLocation + * The location of the breakpoint as specified in the protocol. + */ + _setBreakpoint: function TA__setBreakpoint(aLocation) { + let breakpoints = this._breakpointStore[aLocation.url]; + + // Get or create the breakpoint actor for the given location + let actor; + if (breakpoints[aLocation.line].actor) { + actor = breakpoints[aLocation.line].actor; + } else { + actor = breakpoints[aLocation.line].actor = new BreakpointActor(this, { + url: aLocation.url, + line: aLocation.line + }); + this._hooks.addToParentPool(actor); + } + + // Find all scripts matching the given location + let scripts = this.dbg.findScripts(aLocation); + if (scripts.length == 0) { + return { + error: "noScript", + actor: actor.actorID + }; + } + + /** + * For each script, if the given line has at least one entry point, set + * breakpoint on the bytecode offet for each of them. + */ + let found = false; + for (let script of scripts) { + let offsets = script.getLineOffsets(aLocation.line); + if (offsets.length > 0) { + for (let offset of offsets) { + script.setBreakpoint(offset, actor); + } + actor.addScript(script, this); + found = true; + } + } + if (found) { + return { + actor: actor.actorID + }; + } + + /** + * If we get here, no breakpoint was set. This is because the given line + * has no entry points, for example because it is empty. As a fallback + * strategy, we try to set the breakpoint on the smallest line greater + * than or equal to the given line that as at least one entry point. + */ + + // Find all innermost scripts matching the given location + let scripts = this.dbg.findScripts({ + url: aLocation.url, + line: aLocation.line, + innermost: true + }); + + /** + * For each innermost script, look for the smallest line greater than or + * equal to the given line that has one or more entry points. If found, set + * a breakpoint on the bytecode offset for each of its entry points. + */ + let actualLocation; + let found = false; + for (let script of scripts) { + let offsets = script.getAllOffsets(); + for (let line = aLocation.line; line < offsets.length; ++line) { + if (offsets[line]) { + for (let offset of offsets[line]) { + script.setBreakpoint(offset, actor); + } + actor.addScript(script, this); + if (!actualLocation) { + actualLocation = { + url: aLocation.url, + line: line, + column: 0 + }; + } + found = true; + break; + } + } + } + if (found) { + if (breakpoints[actualLocation.line] && + breakpoints[actualLocation.line].actor) { + /** + * We already have a breakpoint actor for the actual location, so + * actor we created earlier is now redundant. Delete it, update the + * breakpoint store, and return the actor for the actual location. + */ + actor.onDelete(); + delete breakpoints[aLocation.line]; + return { + actor: breakpoints[actualLocation.line].actor.actorID, + actualLocation: actualLocation + }; + } else { + /** + * We don't have a breakpoint actor for the actual location yet. + * Instead or creating a new actor, reuse the actor we created earlier, + * and update the breakpoint store. + */ + actor.location = actualLocation; + breakpoints[actualLocation.line] = breakpoints[aLocation.line]; + delete breakpoints[aLocation.line]; + // WARNING: This overwrites aLocation.line + breakpoints[actualLocation.line].line = actualLocation.line; + return { + actor: actor.actorID, + actualLocation: actualLocation + }; + } + } + + /** + * If we get here, no line matching the given line was found, so just + * epically. + */ + return { + error: "noCodeAtLineColumn", + actor: actor.actorID + }; + }, + + /** + * Get the script and source lists from the debugger. + * + * TODO bug 637572: we should be dealing with sources directly, not inferring + * them through scripts. + */ + _discoverSources: function TA__discoverSources() { + // Only get one script per url. + let scriptsByUrl = {}; + for (let s of this.dbg.findScripts()) { + scriptsByUrl[s.url] = s; + } + + return all([this.sources.sourcesForScript(scriptsByUrl[s]) + for (s of Object.keys(scriptsByUrl))]); + }, + + onSources: function TA_onSources(aRequest) { + return this._discoverSources().then(() => { + return { + sources: [s.form() for (s of this.sources.iter())] + }; + }); + }, + + /** + * Disassociate all breakpoint actors from their scripts and clear the + * breakpoint handlers. This method can be used when the thread actor intends + * to keep the breakpoint store, but needs to clear any actual breakpoints, + * e.g. due to a page navigation. This way the breakpoint actors' script + * caches won't hold on to the Debugger.Script objects leaking memory. + */ + disableAllBreakpoints: function () { + for (let url in this._breakpointStore) { + for (let line in this._breakpointStore[url]) { + let bp = this._breakpointStore[url][line]; + bp.actor.removeScripts(); + } + } + }, + + /** + * Handle a protocol request to pause the debuggee. + */ + onInterrupt: function TA_onInterrupt(aRequest) { + if (this.state == "exited") { + return { type: "exited" }; + } else if (this.state == "paused") { + // TODO: return the actual reason for the existing pause. + return { type: "paused", why: { type: "alreadyPaused" } }; + } else if (this.state != "running") { + return { error: "wrongState", + message: "Received interrupt request in " + this.state + + " state." }; + } + + try { + // Put ourselves in the paused state. + let packet = this._paused(); + if (!packet) { + return { error: "notInterrupted" }; + } + packet.why = { type: "interrupted" }; + + // Send the response to the interrupt request now (rather than + // returning it), because we're going to start a nested event loop + // here. + this.conn.send(packet); + + // Start a nested event loop. + this._nest(); + + // We already sent a response to this request, don't send one + // now. + return null; + } catch (e) { + reportError(e); + return { error: "notInterrupted", message: e.toString() }; + } + }, + + /** + * Return the Debug.Frame for a frame mentioned by the protocol. + */ + _requestFrame: function TA_requestFrame(aFrameID) { + if (!aFrameID) { + return this.youngestFrame; + } + + if (this._framePool.has(aFrameID)) { + return this._framePool.get(aFrameID).frame; + } + + return undefined; + }, + + _paused: function TA_paused(aFrame) { + // We don't handle nested pauses correctly. Don't try - if we're + // paused, just continue running whatever code triggered the pause. + // We don't want to actually have nested pauses (although we + // have nested event loops). If code runs in the debuggee during + // a pause, it should cause the actor to resume (dropping + // pause-lifetime actors etc) and then repause when complete. + + if (this.state === "paused") { + return undefined; + } + + // Clear stepping hooks. + this.dbg.onEnterFrame = undefined; + this.dbg.onExceptionUnwind = undefined; + if (aFrame) { + aFrame.onStep = undefined; + aFrame.onPop = undefined; + } + + this._state = "paused"; + + // Save the pause frame (if any) as the youngest frame for + // stack viewing. + this.youngestFrame = aFrame; + + // Create the actor pool that will hold the pause actor and its + // children. + dbg_assert(!this._pausePool); + this._pausePool = new ActorPool(this.conn); + this.conn.addActorPool(this._pausePool); + + // Give children of the pause pool a quick link back to the + // thread... + this._pausePool.threadActor = this; + + // Create the pause actor itself... + dbg_assert(!this._pauseActor); + this._pauseActor = new PauseActor(this._pausePool); + this._pausePool.addActor(this._pauseActor); + + // Update the list of frames. + let poppedFrames = this._updateFrames(); + + // Send off the paused packet and spin an event loop. + let packet = { from: this.actorID, + type: "paused", + actor: this._pauseActor.actorID }; + if (aFrame) { + packet.frame = this._createFrameActor(aFrame).form(); + } + + if (poppedFrames) { + packet.poppedFrames = poppedFrames; + } + + return packet; + }, + + _nest: function TA_nest() { + if (this._hooks.preNest) { + var nestData = this._hooks.preNest(); + } + + let requestor = Object.create(null); + requestor.url = this._hooks.url; + requestor.connection = this.conn; + DebuggerServer.xpcInspector.enterNestedEventLoop(requestor); + + dbg_assert(this.state === "running"); + + if (this._hooks.postNest) { + this._hooks.postNest(nestData) + } + + // "continue" resumption value. + return undefined; + }, + + _resumed: function TA_resumed() { + this._state = "running"; + + // Drop the actors in the pause actor pool. + this.conn.removeActorPool(this._pausePool); + + this._pausePool = null; + this._pauseActor = null; + this.youngestFrame = null; + + return { from: this.actorID, type: "resumed" }; + }, + + /** + * Expire frame actors for frames that have been popped. + * + * @returns A list of actor IDs whose frames have been popped. + */ + _updateFrames: function TA_updateFrames() { + let popped = []; + + // Create the actor pool that will hold the still-living frames. + let framePool = new ActorPool(this.conn); + let frameList = []; + + for each (let frameActor in this._frameActors) { + if (frameActor.frame.live) { + framePool.addActor(frameActor); + frameList.push(frameActor); + } else { + popped.push(frameActor.actorID); + } + } + + // Remove the old frame actor pool, this will expire + // any actors that weren't added to the new pool. + if (this._framePool) { + this.conn.removeActorPool(this._framePool); + } + + this._frameActors = frameList; + this._framePool = framePool; + this.conn.addActorPool(framePool); + + return popped; + }, + + _createFrameActor: function TA_createFrameActor(aFrame) { + if (aFrame.actor) { + return aFrame.actor; + } + + let actor = new FrameActor(aFrame, this); + this._frameActors.push(actor); + this._framePool.addActor(actor); + aFrame.actor = actor; + + return actor; + }, + + /** + * Create and return an environment actor that corresponds to the provided + * Debugger.Environment. + * @param Debugger.Environment aEnvironment + * The lexical environment we want to extract. + * @param object aPool + * The pool where the newly-created actor will be placed. + * @return The EnvironmentActor for aEnvironment or undefined for host + * functions or functions scoped to a non-debuggee global. + */ + createEnvironmentActor: + function TA_createEnvironmentActor(aEnvironment, aPool) { + if (!aEnvironment) { + return undefined; + } + + if (aEnvironment.actor) { + return aEnvironment.actor; + } + + let actor = new EnvironmentActor(aEnvironment, this); + this._environmentActors.push(actor); + aPool.addActor(actor); + aEnvironment.actor = actor; + + return actor; + }, + + /** + * Create a grip for the given debuggee value. If the value is an + * object, will create an actor with the given lifetime. + */ + createValueGrip: function TA_createValueGrip(aValue, aPool=false) { + if (!aPool) { + aPool = this._pausePool; + } + let type = typeof(aValue); + + if (type === "string" && this._stringIsLong(aValue)) { + return this.longStringGrip(aValue, aPool); + } + + if (type === "boolean" || type === "string" || type === "number") { + return aValue; + } + + if (aValue === null) { + return { type: "null" }; + } + + if (aValue === undefined) { + return { type: "undefined" } + } + + if (typeof(aValue) === "object") { + return this.objectGrip(aValue, aPool); + } + + dbg_assert(false, "Failed to provide a grip for: " + aValue); + return null; + }, + + /** + * Return a protocol completion value representing the given + * Debugger-provided completion value. + */ + createProtocolCompletionValue: + function TA_createProtocolCompletionValue(aCompletion) { + let protoValue = {}; + if ("return" in aCompletion) { + protoValue.return = this.createValueGrip(aCompletion.return); + } else if ("yield" in aCompletion) { + protoValue.return = this.createValueGrip(aCompletion.yield); + } else if ("throw" in aCompletion) { + protoValue.throw = this.createValueGrip(aCompletion.throw); + } else { + protoValue.terminated = true; + } + return protoValue; + }, + + /** + * Create a grip for the given debuggee object. + * + * @param aValue Debugger.Object + * The debuggee object value. + * @param aPool ActorPool + * The actor pool where the new object actor will be added. + */ + objectGrip: function TA_objectGrip(aValue, aPool) { + if (!aPool.objectActors) { + aPool.objectActors = new WeakMap(); + } + + if (aPool.objectActors.has(aValue)) { + return aPool.objectActors.get(aValue).grip(); + } else if (this.threadLifetimePool.objectActors.has(aValue)) { + return this.threadLifetimePool.objectActors.get(aValue).grip(); + } + + let actor = new PauseScopedObjectActor(aValue, this); + aPool.addActor(actor); + aPool.objectActors.set(aValue, actor); + return actor.grip(); + }, + + /** + * Create a grip for the given debuggee object with a pause lifetime. + * + * @param aValue Debugger.Object + * The debuggee object value. + */ + pauseObjectGrip: function TA_pauseObjectGrip(aValue) { + if (!this._pausePool) { + throw "Object grip requested while not paused."; + } + + return this.objectGrip(aValue, this._pausePool); + }, + + /** + * Extend the lifetime of the provided object actor to thread lifetime. + * + * @param aActor object + * The object actor. + */ + threadObjectGrip: function TA_threadObjectGrip(aActor) { + // We want to reuse the existing actor ID, so we just remove it from the + // current pool's weak map and then let pool.addActor do the rest. + aActor.registeredPool.objectActors.delete(aActor.obj); + this.threadLifetimePool.addActor(aActor); + this.threadLifetimePool.objectActors.set(aActor.obj, aActor); + }, + + /** + * Handle a protocol request to promote multiple pause-lifetime grips to + * thread-lifetime grips. + * + * @param aRequest object + * The protocol request object. + */ + onThreadGrips: function OA_onThreadGrips(aRequest) { + if (this.state != "paused") { + return { error: "wrongState" }; + } + + if (!aRequest.actors) { + return { error: "missingParameter", + message: "no actors were specified" }; + } + + for (let actorID of aRequest.actors) { + let actor = this._pausePool.get(actorID); + if (actor) { + this.threadObjectGrip(actor); + } + } + return {}; + }, + + /** + * Create a grip for the given string. + * + * @param aString String + * The string we are creating a grip for. + * @param aPool ActorPool + * The actor pool where the new actor will be added. + */ + longStringGrip: function TA_longStringGrip(aString, aPool) { + if (!aPool.longStringActors) { + aPool.longStringActors = {}; + } + + if (aPool.longStringActors.hasOwnProperty(aString)) { + return aPool.longStringActors[aString].grip(); + } + + let actor = new LongStringActor(aString, this); + aPool.addActor(actor); + aPool.longStringActors[aString] = actor; + return actor.grip(); + }, + + /** + * Create a long string grip that is scoped to a pause. + * + * @param aString String + * The string we are creating a grip for. + */ + pauseLongStringGrip: function TA_pauseLongStringGrip (aString) { + return this.longStringGrip(aString, this._pausePool); + }, + + /** + * Create a long string grip that is scoped to a thread. + * + * @param aString String + * The string we are creating a grip for. + */ + threadLongStringGrip: function TA_pauseLongStringGrip (aString) { + return this.longStringGrip(aString, this._threadLifetimePool); + }, + + /** + * Returns true if the string is long enough to use a LongStringActor instead + * of passing the value directly over the protocol. + * + * @param aString String + * The string we are checking the length of. + */ + _stringIsLong: function TA__stringIsLong(aString) { + return aString.length >= DebuggerServer.LONG_STRING_LENGTH; + }, + + // JS Debugger API hooks. + + /** + * A function that the engine calls when a call to a debug event hook, + * breakpoint handler, watchpoint handler, or similar function throws some + * exception. + * + * @param aException exception + * The exception that was thrown in the debugger code. + */ + uncaughtExceptionHook: function TA_uncaughtExceptionHook(aException) { + dumpn("Got an exception: " + aException.message + "\n" + aException.stack); + }, + + /** + * A function that the engine calls when a debugger statement has been + * executed in the specified frame. + * + * @param aFrame Debugger.Frame + * The stack frame that contained the debugger statement. + */ + onDebuggerStatement: function TA_onDebuggerStatement(aFrame) { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + return this._pauseAndRespond(aFrame, { type: "debuggerStatement" }); + }, + + /** + * A function that the engine calls when an exception has been thrown and has + * propagated to the specified frame. + * + * @param aFrame Debugger.Frame + * The youngest remaining stack frame. + * @param aValue object + * The exception that was thrown. + */ + onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) { + if (this.sources.isBlackBoxed(aFrame.script.url)) { + return undefined; + } + try { + let packet = this._paused(aFrame); + if (!packet) { + return undefined; + } + + packet.why = { type: "exception", + exception: this.createValueGrip(aValue) }; + this.conn.send(packet); + return this._nest(); + } catch(e) { + log("Got an exception during TA_onExceptionUnwind: " + e + + ": " + e.stack); + return undefined; + } + }, + + /** + * A function that the engine calls when a new script has been loaded into the + * scope of the specified debuggee global. + * + * @param aScript Debugger.Script + * The source script that has been loaded into a debuggee compartment. + * @param aGlobal Debugger.Object + * A Debugger.Object instance whose referent is the global object. + */ + onNewScript: function TA_onNewScript(aScript, aGlobal) { + this._addScript(aScript); + this.sources.sourcesForScript(aScript); + }, + + onNewSource: function TA_onNewSource(aSource) { + this.conn.send({ + from: this.actorID, + type: "newSource", + source: aSource.form() + }); + }, + + /** + * Check if scripts from the provided source URL are allowed to be stored in + * the cache. + * + * @param aSourceUrl String + * The url of the script's source that will be stored. + * @returns true, if the script can be added, false otherwise. + */ + _allowSource: function TA__allowSource(aSourceUrl) { + // Ignore anything we don't have a URL for (eval scripts, for example). + if (!aSourceUrl) + return false; + // Ignore XBL bindings for content debugging. + if (aSourceUrl.indexOf("chrome://") == 0) { + return false; + } + // Ignore about:* pages for content debugging. + if (aSourceUrl.indexOf("about:") == 0) { + return false; + } + return true; + }, + + /** + * Restore any pre-existing breakpoints to the scripts that we have access to. + */ + _restoreBreakpoints: function TA__restoreBreakpoints() { + for (let s of this.dbg.findScripts()) { + this._addScript(s); + } + }, + + /** + * Add the provided script to the server cache. + * + * @param aScript Debugger.Script + * The source script that will be stored. + * @returns true, if the script was added; false otherwise. + */ + _addScript: function TA__addScript(aScript) { + if (!this._allowSource(aScript.url)) { + return false; + } + + // Set any stored breakpoints. + let existing = this._breakpointStore[aScript.url]; + if (existing) { + let endLine = aScript.startLine + aScript.lineCount - 1; + // Iterate over the lines backwards, so that sliding breakpoints don't + // affect the loop. + for (let line = existing.length - 1; line >= aScript.startLine; line--) { + let bp = existing[line]; + // Only consider breakpoints that are not already associated with + // scripts, and limit search to the line numbers contained in the new + // script. + if (bp && !bp.actor.scripts.length && line <= endLine) { + this._setBreakpoint(bp); + } + } + } + return true; + }, + +}; + +ThreadActor.prototype.requestTypes = { + "attach": ThreadActor.prototype.onAttach, + "detach": ThreadActor.prototype.onDetach, + "reconfigure": ThreadActor.prototype.onReconfigure, + "resume": ThreadActor.prototype.onResume, + "clientEvaluate": ThreadActor.prototype.onClientEvaluate, + "frames": ThreadActor.prototype.onFrames, + "interrupt": ThreadActor.prototype.onInterrupt, + "releaseMany": ThreadActor.prototype.onReleaseMany, + "setBreakpoint": ThreadActor.prototype.onSetBreakpoint, + "sources": ThreadActor.prototype.onSources, + "threadGrips": ThreadActor.prototype.onThreadGrips +}; + + +/** + * Creates a PauseActor. + * + * PauseActors exist for the lifetime of a given debuggee pause. Used to + * scope pause-lifetime grips. + * + * @param ActorPool aPool + * The actor pool created for this pause. + */ +function PauseActor(aPool) +{ + this.pool = aPool; +} + +PauseActor.prototype = { + actorPrefix: "pause" +}; + + +/** + * A base actor for any actors that should only respond receive messages in the + * paused state. Subclasses may expose a `threadActor` which is used to help + * determine when we are in a paused state. Subclasses should set their own + * "constructor" property if they want better error messages. You should never + * instantiate a PauseScopedActor directly, only through subclasses. + */ +function PauseScopedActor() +{ +} + +/** + * A function decorator for creating methods to handle protocol messages that + * should only be received while in the paused state. + * + * @param aMethod Function + * The function we are decorating. + */ +PauseScopedActor.withPaused = function PSA_withPaused(aMethod) { + return function () { + if (this.isPaused()) { + return aMethod.apply(this, arguments); + } else { + return this._wrongState(); + } + }; +}; + +PauseScopedActor.prototype = { + + /** + * Returns true if we are in the paused state. + */ + isPaused: function PSA_isPaused() { + // When there is not a ThreadActor available (like in the webconsole) we + // have to be optimistic and assume that we are paused so that we can + // respond to requests. + return this.threadActor ? this.threadActor.state === "paused" : true; + }, + + /** + * Returns the wrongState response packet for this actor. + */ + _wrongState: function PSA_wrongState() { + return { + error: "wrongState", + message: this.constructor.name + + " actors can only be accessed while the thread is paused." + }; + } +}; + + +/** + * A SourceActor provides information about the source of a script. + * + * @param aUrl String + * The url of the source we are representing. + * @param aThreadActor ThreadActor + * The current thread actor. + * @param aSourceMap SourceMapConsumer + * Optional. The source map that introduced this source, if available. + */ +function SourceActor(aUrl, aThreadActor, aSourceMap=null) { + this._threadActor = aThreadActor; + this._url = aUrl; + this._sourceMap = aSourceMap; +} + +SourceActor.prototype = { + constructor: SourceActor, + actorPrefix: "source", + + get threadActor() this._threadActor, + get url() this._url, + + form: function SA_form() { + return { + actor: this.actorID, + url: this._url, + isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url) + // TODO bug 637572: introductionScript + }; + }, + + disconnect: function LSA_disconnect() { + if (this.registeredPool && this.registeredPool.sourceActors) { + delete this.registeredPool.sourceActors[this.actorID]; + } + }, + + /** + * Handler for the "source" packet. + */ + onSource: function SA_onSource(aRequest) { + let sourceContent = null; + if (this._sourceMap) { + sourceContent = this._sourceMap.sourceContentFor(this._url); + } + + if (sourceContent) { + return { + from: this.actorID, + source: this.threadActor.createValueGrip( + sourceContent, this.threadActor.threadLifetimePool) + }; + } + + // XXX bug 865252: Don't load from the cache if this is a source mapped + // source because we can't guarantee that the cache has the most up to date + // content for this source like we can if it isn't source mapped. + return fetch(this._url, { loadFromCache: !this._sourceMap }) + .then((aSource) => { + return this.threadActor.createValueGrip( + aSource, this.threadActor.threadLifetimePool); + }) + .then((aSourceGrip) => { + return { + from: this.actorID, + source: aSourceGrip + }; + }, (aError) => { + let msg = "Got an exception during SA_onSource: " + aError + + "\n" + aError.stack; + // Cu.reportError(msg); + dumpn(msg); + return { + "from": this.actorID, + "error": "loadSourceError", + "message": "Could not load the source for " + this._url + "." + }; + }); + }, + + /** + * Handler for the "blackbox" packet. + */ + onBlackBox: function SA_onBlackBox(aRequest) { + this.threadActor.sources.blackBox(this.url); + let packet = { + from: this.actorID + }; + if (this.threadActor.state == "paused" + && this.threadActor.youngestFrame + && this.threadActor.youngestFrame.script.url == this.url) { + packet.pausedInSource = true; + } + return packet; + }, + + /** + * Handler for the "unblackbox" packet. + */ + onUnblackBox: function SA_onUnblackBox(aRequest) { + this.threadActor.sources.unblackBox(this.url); + return { + from: this.actorID + }; + } +}; + +SourceActor.prototype.requestTypes = { + "source": SourceActor.prototype.onSource, + "blackbox": SourceActor.prototype.onBlackBox, + "unblackbox": SourceActor.prototype.onUnblackBox +}; + + +/** + * Creates an actor for the specified object. + * + * @param aObj Debugger.Object + * The debuggee object. + * @param aThreadActor ThreadActor + * The parent thread actor for this object. + */ +function ObjectActor(aObj, aThreadActor) +{ + this.obj = aObj; + this.threadActor = aThreadActor; +} + +ObjectActor.prototype = { + actorPrefix: "obj", + + /** + * Returns a grip for this actor for returning in a protocol message. + */ + grip: function OA_grip() { + let g = { + "type": "object", + "class": this.obj.class, + "actor": this.actorID, + "extensible": this.obj.isExtensible(), + "frozen": this.obj.isFrozen(), + "sealed": this.obj.isSealed() + }; + + // Add additional properties for functions. + if (this.obj.class === "Function") { + if (this.obj.name) { + g.name = this.obj.name; + } else if (this.obj.displayName) { + g.displayName = this.obj.displayName; + } + + // Check if the developer has added a de-facto standard displayName + // property for us to use. + let desc = this.obj.getOwnPropertyDescriptor("displayName"); + if (desc && desc.value && typeof desc.value == "string") { + g.userDisplayName = this.threadActor.createValueGrip(desc.value); + } + } + + return g; + }, + + /** + * Releases this actor from the pool. + */ + release: function OA_release() { + if (this.registeredPool.objectActors) { + this.registeredPool.objectActors.delete(this.obj); + } + this.registeredPool.removeActor(this); + }, + + /** + * Handle a protocol request to provide the names of the properties defined on + * the object and not its prototype. + * + * @param aRequest object + * The protocol request object. + */ + onOwnPropertyNames: function OA_onOwnPropertyNames(aRequest) { + return { from: this.actorID, + ownPropertyNames: this.obj.getOwnPropertyNames() }; + }, + + /** + * Handle a protocol request to provide the prototype and own properties of + * the object. + * + * @param aRequest object + * The protocol request object. + */ + onPrototypeAndProperties: function OA_onPrototypeAndProperties(aRequest) { + let ownProperties = Object.create(null); + let names; + try { + names = this.obj.getOwnPropertyNames(); + } catch (ex) { + // The above can throw if this.obj points to a dead object. + // TODO: we should use Cu.isDeadWrapper() - see bug 885800. + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(null), + ownProperties: ownProperties, + safeGetterValues: Object.create(null) }; + } + for (let name of names) { + ownProperties[name] = this._propertyDescriptor(name); + } + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(this.obj.proto), + ownProperties: ownProperties, + safeGetterValues: this._findSafeGetterValues(ownProperties) }; + }, + + /** + * Find the safe getter values for the current Debugger.Object, |this.obj|. + * + * @private + * @param object aOwnProperties + * The object that holds the list of known ownProperties for + * |this.obj|. + * @return object + * An object that maps property names to safe getter descriptors as + * defined by the remote debugging protocol. + */ + _findSafeGetterValues: function OA__findSafeGetterValues(aOwnProperties) + { + let safeGetterValues = Object.create(null); + let obj = this.obj; + let level = 0; + + while (obj) { + let getters = this._findSafeGetters(obj); + for (let name of getters) { + // Avoid overwriting properties from prototypes closer to this.obj. Also + // avoid providing safeGetterValues from prototypes if property |name| + // is already defined as an own property. + if (name in safeGetterValues || + (obj != this.obj && name in aOwnProperties)) { + continue; + } + + let desc = null, getter = null; + try { + desc = obj.getOwnPropertyDescriptor(name); + getter = desc.get; + } catch (ex) { + // The above can throw if the cache becomes stale. + } + if (!getter) { + obj._safeGetters = null; + continue; + } + + let result = getter.call(this.obj); + if (result && !("throw" in result)) { + let getterValue = undefined; + if ("return" in result) { + getterValue = result.return; + } else if ("yield" in result) { + getterValue = result.yield; + } + // WebIDL attributes specified with the LenientThis extended attribute + // return undefined and should be ignored. + if (getterValue !== undefined) { + safeGetterValues[name] = { + getterValue: this.threadActor.createValueGrip(getterValue), + getterPrototypeLevel: level, + enumerable: desc.enumerable, + writable: level == 0 ? desc.writable : true, + }; + } + } + } + + obj = obj.proto; + level++; + } + + return safeGetterValues; + }, + + /** + * Find the safe getters for a given Debugger.Object. Safe getters are native + * getters which are safe to execute. + * + * @private + * @param Debugger.Object aObject + * The Debugger.Object where you want to find safe getters. + * @return Set + * A Set of names of safe getters. This result is cached for each + * Debugger.Object. + */ + _findSafeGetters: function OA__findSafeGetters(aObject) + { + if (aObject._safeGetters) { + return aObject._safeGetters; + } + + let getters = new Set(); + for (let name of aObject.getOwnPropertyNames()) { + let desc = null; + try { + desc = aObject.getOwnPropertyDescriptor(name); + } catch (e) { + // Calling getOwnPropertyDescriptor on wrapped native prototypes is not + // allowed (bug 560072). + } + if (!desc || desc.value !== undefined || !("get" in desc)) { + continue; + } + + let fn = desc.get; + if (fn && fn.callable && fn.class == "Function" && + fn.script === undefined) { + getters.add(name); + } + } + + aObject._safeGetters = getters; + return getters; + }, + + /** + * Handle a protocol request to provide the prototype of the object. + * + * @param aRequest object + * The protocol request object. + */ + onPrototype: function OA_onPrototype(aRequest) { + return { from: this.actorID, + prototype: this.threadActor.createValueGrip(this.obj.proto) }; + }, + + /** + * Handle a protocol request to provide the property descriptor of the + * object's specified property. + * + * @param aRequest object + * The protocol request object. + */ + onProperty: function OA_onProperty(aRequest) { + if (!aRequest.name) { + return { error: "missingParameter", + message: "no property name was specified" }; + } + + return { from: this.actorID, + descriptor: this._propertyDescriptor(aRequest.name) }; + }, + + /** + * A helper method that creates a property descriptor for the provided object, + * properly formatted for sending in a protocol response. + * + * @param string aName + * The property that the descriptor is generated for. + */ + _propertyDescriptor: function OA_propertyDescriptor(aName) { + let desc; + try { + desc = this.obj.getOwnPropertyDescriptor(aName); + } catch (e) { + // Calling getOwnPropertyDescriptor on wrapped native prototypes is not + // allowed (bug 560072). Inform the user with a bogus, but hopefully + // explanatory, descriptor. + return { + configurable: false, + writable: false, + enumerable: false, + value: e.name + }; + } + + let retval = { + configurable: desc.configurable, + enumerable: desc.enumerable + }; + + if ("value" in desc) { + retval.writable = desc.writable; + retval.value = this.threadActor.createValueGrip(desc.value); + } else { + if ("get" in desc) { + retval.get = this.threadActor.createValueGrip(desc.get); + } + if ("set" in desc) { + retval.set = this.threadActor.createValueGrip(desc.set); + } + } + return retval; + }, + + /** + * Handle a protocol request to provide the source code of a function. + * + * @param aRequest object + * The protocol request object. + */ + onDecompile: function OA_onDecompile(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "decompile request is only valid for object grips " + + "with a 'Function' class." }; + } + + return { from: this.actorID, + decompiledCode: this.obj.decompile(!!aRequest.pretty) }; + }, + + /** + * Handle a protocol request to provide the parameters of a function. + * + * @param aRequest object + * The protocol request object. + */ + onParameterNames: function OA_onParameterNames(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "'parameterNames' request is only valid for object " + + "grips with a 'Function' class." }; + } + + return { parameterNames: this.obj.parameterNames }; + }, + + /** + * Handle a protocol request to release a thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onRelease: function OA_onRelease(aRequest) { + this.release(); + return {}; + }, +}; + +ObjectActor.prototype.requestTypes = { + "parameterNames": ObjectActor.prototype.onParameterNames, + "prototypeAndProperties": ObjectActor.prototype.onPrototypeAndProperties, + "prototype": ObjectActor.prototype.onPrototype, + "property": ObjectActor.prototype.onProperty, + "ownPropertyNames": ObjectActor.prototype.onOwnPropertyNames, + "decompile": ObjectActor.prototype.onDecompile, + "release": ObjectActor.prototype.onRelease, +}; + + +/** + * Creates a pause-scoped actor for the specified object. + * @see ObjectActor + */ +function PauseScopedObjectActor() +{ + ObjectActor.apply(this, arguments); +} + +PauseScopedObjectActor.prototype = Object.create(PauseScopedActor.prototype); + +update(PauseScopedObjectActor.prototype, ObjectActor.prototype); + +update(PauseScopedObjectActor.prototype, { + constructor: PauseScopedObjectActor, + + onOwnPropertyNames: + PauseScopedActor.withPaused(ObjectActor.prototype.onOwnPropertyNames), + + onPrototypeAndProperties: + PauseScopedActor.withPaused(ObjectActor.prototype.onPrototypeAndProperties), + + onPrototype: PauseScopedActor.withPaused(ObjectActor.prototype.onPrototype), + onProperty: PauseScopedActor.withPaused(ObjectActor.prototype.onProperty), + onDecompile: PauseScopedActor.withPaused(ObjectActor.prototype.onDecompile), + + onParameterNames: + PauseScopedActor.withPaused(ObjectActor.prototype.onParameterNames), + + /** + * Handle a protocol request to provide the lexical scope of a function. + * + * @param aRequest object + * The protocol request object. + */ + onScope: PauseScopedActor.withPaused(function OA_onScope(aRequest) { + if (this.obj.class !== "Function") { + return { error: "objectNotFunction", + message: "scope request is only valid for object grips with a" + + " 'Function' class." }; + } + + let envActor = this.threadActor.createEnvironmentActor(this.obj.environment, + this.registeredPool); + if (!envActor) { + return { error: "notDebuggee", + message: "cannot access the environment of this function." }; + } + + return { from: this.actorID, scope: envActor.form() }; + }), + + /** + * Handle a protocol request to promote a pause-lifetime grip to a + * thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onThreadGrip: PauseScopedActor.withPaused(function OA_onThreadGrip(aRequest) { + this.threadActor.threadObjectGrip(this); + return {}; + }), + + /** + * Handle a protocol request to release a thread-lifetime grip. + * + * @param aRequest object + * The protocol request object. + */ + onRelease: PauseScopedActor.withPaused(function OA_onRelease(aRequest) { + if (this.registeredPool !== this.threadActor.threadLifetimePool) { + return { error: "notReleasable", + message: "Only thread-lifetime actors can be released." }; + } + + this.release(); + return {}; + }), +}); + +update(PauseScopedObjectActor.prototype.requestTypes, { + "scope": PauseScopedObjectActor.prototype.onScope, + "threadGrip": PauseScopedObjectActor.prototype.onThreadGrip, +}); + + +/** + * Creates an actor for the specied "very long" string. "Very long" is specified + * at the server's discretion. + * + * @param aString String + * The string. + */ +function LongStringActor(aString) +{ + this.string = aString; + this.stringLength = aString.length; +} + +LongStringActor.prototype = { + + actorPrefix: "longString", + + disconnect: function LSA_disconnect() { + // Because longStringActors is not a weak map, we won't automatically leave + // it so we need to manually leave on disconnect so that we don't leak + // memory. + if (this.registeredPool && this.registeredPool.longStringActors) { + delete this.registeredPool.longStringActors[this.actorID]; + } + }, + + /** + * Returns a grip for this actor for returning in a protocol message. + */ + grip: function LSA_grip() { + return { + "type": "longString", + "initial": this.string.substring( + 0, DebuggerServer.LONG_STRING_INITIAL_LENGTH), + "length": this.stringLength, + "actor": this.actorID + }; + }, + + /** + * Handle a request to extract part of this actor's string. + * + * @param aRequest object + * The protocol request object. + */ + onSubstring: function LSA_onSubString(aRequest) { + return { + "from": this.actorID, + "substring": this.string.substring(aRequest.start, aRequest.end) + }; + }, + + /** + * Handle a request to release this LongStringActor instance. + */ + onRelease: function LSA_onRelease() { + // TODO: also check if registeredPool === threadActor.threadLifetimePool + // when the web console moves aray from manually releasing pause-scoped + // actors. + if (this.registeredPool.longStringActors) { + delete this.registeredPool.longStringActors[this.actorID]; + } + this.registeredPool.removeActor(this); + return {}; + }, +}; + +LongStringActor.prototype.requestTypes = { + "substring": LongStringActor.prototype.onSubstring, + "release": LongStringActor.prototype.onRelease +}; + + +/** + * Creates an actor for the specified stack frame. + * + * @param aFrame Debugger.Frame + * The debuggee frame. + * @param aThreadActor ThreadActor + * The parent thread actor for this frame. + */ +function FrameActor(aFrame, aThreadActor) +{ + this.frame = aFrame; + this.threadActor = aThreadActor; +} + +FrameActor.prototype = { + actorPrefix: "frame", + + /** + * A pool that contains frame-lifetime objects, like the environment. + */ + _frameLifetimePool: null, + get frameLifetimePool() { + if (!this._frameLifetimePool) { + this._frameLifetimePool = new ActorPool(this.conn); + this.conn.addActorPool(this._frameLifetimePool); + } + return this._frameLifetimePool; + }, + + /** + * Finalization handler that is called when the actor is being evicted from + * the pool. + */ + disconnect: function FA_disconnect() { + this.conn.removeActorPool(this._frameLifetimePool); + this._frameLifetimePool = null; + }, + + /** + * Returns a frame form for use in a protocol message. + */ + form: function FA_form() { + let form = { actor: this.actorID, + type: this.frame.type }; + if (this.frame.type === "call") { + form.callee = this.threadActor.createValueGrip(this.frame.callee); + } + + if (this.frame.environment) { + let envActor = this.threadActor + .createEnvironmentActor(this.frame.environment, + this.frameLifetimePool); + form.environment = envActor.form(); + } + form.this = this.threadActor.createValueGrip(this.frame.this); + form.arguments = this._args(); + if (this.frame.script) { + form.where = { url: this.frame.script.url, + line: this.frame.script.getOffsetLine(this.frame.offset) }; + form.isBlackBoxed = this.threadActor.sources.isBlackBoxed(this.frame.script.url) + } + + if (!this.frame.older) { + form.oldest = true; + } + + return form; + }, + + _args: function FA__args() { + if (!this.frame.arguments) { + return []; + } + + return [this.threadActor.createValueGrip(arg) + for each (arg in this.frame.arguments)]; + }, + + /** + * Handle a protocol request to pop this frame from the stack. + * + * @param aRequest object + * The protocol request object. + */ + onPop: function FA_onPop(aRequest) { + // TODO: remove this when Debugger.Frame.prototype.pop is implemented + if (typeof this.frame.pop != "function") { + return { error: "notImplemented", + message: "Popping frames is not yet implemented." }; + } + + while (this.frame != this.threadActor.dbg.getNewestFrame()) { + this.threadActor.dbg.getNewestFrame().pop(); + } + this.frame.pop(aRequest.completionValue); + + // TODO: return the watches property when frame pop watch actors are + // implemented. + return { from: this.actorID }; + } +}; + +FrameActor.prototype.requestTypes = { + "pop": FrameActor.prototype.onPop, +}; + + +/** + * Creates a BreakpointActor. BreakpointActors exist for the lifetime of their + * containing thread and are responsible for deleting breakpoints, handling + * breakpoint hits and associating breakpoints with scripts. + * + * @param ThreadActor aThreadActor + * The parent thread actor that contains this breakpoint. + * @param object aLocation + * The location of the breakpoint as specified in the protocol. + */ +function BreakpointActor(aThreadActor, aLocation) +{ + this.scripts = []; + this.threadActor = aThreadActor; + this.location = aLocation; +} + +BreakpointActor.prototype = { + actorPrefix: "breakpoint", + + /** + * Called when this same breakpoint is added to another Debugger.Script + * instance, in the case of a page reload. + * + * @param aScript Debugger.Script + * The new source script on which the breakpoint has been set. + * @param ThreadActor aThreadActor + * The parent thread actor that contains this breakpoint. + */ + addScript: function BA_addScript(aScript, aThreadActor) { + this.threadActor = aThreadActor; + this.scripts.push(aScript); + }, + + /** + * Remove the breakpoints from associated scripts and clear the script cache. + */ + removeScripts: function () { + for (let script of this.scripts) { + script.clearBreakpoint(this); + } + this.scripts = []; + }, + + /** + * A function that the engine calls when a breakpoint has been hit. + * + * @param aFrame Debugger.Frame + * The stack frame that contained the breakpoint. + */ + hit: function BA_hit(aFrame) { + if (this.threadActor.sources.isBlackBoxed(this.location.url)) { + return undefined; + } + + // TODO: add the rest of the breakpoints on that line (bug 676602). + let reason = { type: "breakpoint", actors: [ this.actorID ] }; + return this.threadActor._pauseAndRespond(aFrame, reason, (aPacket) => { + log("pause callback ..."); + + let { url, line } = aPacket.frame.where; + return this.threadActor.sources.getOriginalLocation(url, line) + .then(function (aOrigPosition) { + aPacket.frame.where = aOrigPosition; + return aPacket; + }); + }); + }, + + /** + * Handle a protocol request to remove this breakpoint. + * + * @param aRequest object + * The protocol request object. + */ + onDelete: function BA_onDelete(aRequest) { + // Remove from the breakpoint store. + let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url]; + delete scriptBreakpoints[this.location.line]; + this.threadActor._hooks.removeFromParentPool(this); + // Remove the actual breakpoint from the associated scripts. + this.removeScripts(); + + return { from: this.actorID }; + } +}; + +BreakpointActor.prototype.requestTypes = { + "delete": BreakpointActor.prototype.onDelete +}; + + +/** + * Creates an EnvironmentActor. EnvironmentActors are responsible for listing + * the bindings introduced by a lexical environment and assigning new values to + * those identifier bindings. + * + * @param Debugger.Environment aEnvironment + * The lexical environment that will be used to create the actor. + * @param ThreadActor aThreadActor + * The parent thread actor that contains this environment. + */ +function EnvironmentActor(aEnvironment, aThreadActor) +{ + this.obj = aEnvironment; + this.threadActor = aThreadActor; +} + +EnvironmentActor.prototype = { + actorPrefix: "environment", + + /** + * Return an environment form for use in a protocol message. + */ + form: function EA_form() { + let form = { actor: this.actorID }; + + // What is this environment's type? + if (this.obj.type == "declarative") { + form.type = this.obj.callee ? "function" : "block"; + } else { + form.type = this.obj.type; + } + + // Does this environment have a parent? + if (this.obj.parent) { + form.parent = (this.threadActor + .createEnvironmentActor(this.obj.parent, + this.registeredPool) + .form()); + } + + // Does this environment reflect the properties of an object as variables? + if (this.obj.type == "object" || this.obj.type == "with") { + form.object = this.threadActor.createValueGrip(this.obj.object); + } + + // Is this the environment created for a function call? + if (this.obj.callee) { + form.function = this.threadActor.createValueGrip(this.obj.callee); + } + + // Shall we list this environment's bindings? + if (this.obj.type == "declarative") { + form.bindings = this._bindings(); + } + + return form; + }, + + /** + * Return the identifier bindings object as required by the remote protocol + * specification. + */ + _bindings: function EA_bindings() { + let bindings = { arguments: [], variables: {} }; + + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands (bug 725815). + if (typeof this.obj.getVariable != "function") { + //if (typeof this.obj.getVariableDescriptor != "function") { + return bindings; + } + + let parameterNames; + if (this.obj.callee) { + parameterNames = this.obj.callee.parameterNames; + } + for each (let name in parameterNames) { + let arg = {}; + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands (bug 725815). + let desc = { + value: this.obj.getVariable(name), + configurable: false, + writable: true, + enumerable: true + }; + + // let desc = this.obj.getVariableDescriptor(name); + let descForm = { + enumerable: true, + configurable: desc.configurable + }; + if ("value" in desc) { + descForm.value = this.threadActor.createValueGrip(desc.value); + descForm.writable = desc.writable; + } else { + descForm.get = this.threadActor.createValueGrip(desc.get); + descForm.set = this.threadActor.createValueGrip(desc.set); + } + arg[name] = descForm; + bindings.arguments.push(arg); + } + + for each (let name in this.obj.names()) { + if (bindings.arguments.some(function exists(element) { + return !!element[name]; + })) { + continue; + } + + // TODO: this part should be removed in favor of the commented-out part + // below when getVariableDescriptor lands. + let desc = { + configurable: false, + writable: true, + enumerable: true + }; + try { + desc.value = this.obj.getVariable(name); + } catch (e) { + // Avoid "Debugger scope is not live" errors for |arguments|, introduced + // in bug 746601. + if (name != "arguments") { + throw e; + } + } + //let desc = this.obj.getVariableDescriptor(name); + let descForm = { + enumerable: true, + configurable: desc.configurable + }; + if ("value" in desc) { + descForm.value = this.threadActor.createValueGrip(desc.value); + descForm.writable = desc.writable; + } else { + descForm.get = this.threadActor.createValueGrip(desc.get); + descForm.set = this.threadActor.createValueGrip(desc.set); + } + bindings.variables[name] = descForm; + } + + return bindings; + }, + + /** + * Handle a protocol request to change the value of a variable bound in this + * lexical environment. + * + * @param aRequest object + * The protocol request object. + */ + onAssign: function EA_onAssign(aRequest) { + // TODO: enable the commented-out part when getVariableDescriptor lands + // (bug 725815). + /*let desc = this.obj.getVariableDescriptor(aRequest.name); + + if (!desc.writable) { + return { error: "immutableBinding", + message: "Changing the value of an immutable binding is not " + + "allowed" }; + }*/ + + try { + this.obj.setVariable(aRequest.name, aRequest.value); + } catch (e) { + if (e instanceof Debugger.DebuggeeWouldRun) { + return { error: "threadWouldRun", + cause: e.cause ? e.cause : "setter", + message: "Assigning a value would cause the debuggee to run" }; + } + // This should never happen, so let it complain loudly if it does. + throw e; + } + return { from: this.actorID }; + }, + + /** + * Handle a protocol request to fully enumerate the bindings introduced by the + * lexical environment. + * + * @param aRequest object + * The protocol request object. + */ + onBindings: function EA_onBindings(aRequest) { + return { from: this.actorID, + bindings: this._bindings() }; + } +}; + +EnvironmentActor.prototype.requestTypes = { + "assign": EnvironmentActor.prototype.onAssign, + "bindings": EnvironmentActor.prototype.onBindings +}; + +/** + * Override the toString method in order to get more meaningful script output + * for debugging the debugger. + */ +Debugger.Script.prototype.toString = function() { + let output = ""; + if (this.url) { + output += this.url; + } + if (typeof this.startLine != "undefined") { + output += ":" + this.startLine; + if (this.lineCount && this.lineCount > 1) { + output += "-" + (this.startLine + this.lineCount - 1); + } + } + if (this.strictMode) { + output += ":strict"; + } + return output; +}; + +/** + * Helper property for quickly getting to the line number a stack frame is + * currently paused at. + */ +Object.defineProperty(Debugger.Frame.prototype, "line", { + configurable: true, + get: function() { + if (this.script) { + return this.script.getOffsetLine(this.offset); + } else { + return null; + } + } +}); + + +/** + * Creates an actor for handling chrome debugging. ChromeDebuggerActor is a + * thin wrapper over ThreadActor, slightly changing some of its behavior. + * + * @param aConnection object + * The DebuggerServerConnection with which this ChromeDebuggerActor + * is associated. (Currently unused, but required to make this + * constructor usable with addGlobalActor.) + * + * @param aHooks object + * An object with preNest and postNest methods for calling when entering + * and exiting a nested event loop and also addToParentPool and + * removeFromParentPool methods for handling the lifetime of actors that + * will outlive the thread, like breakpoints. + */ +function ChromeDebuggerActor(aConnection, aHooks) +{ + ThreadActor.call(this, aHooks); +} + +ChromeDebuggerActor.prototype = Object.create(ThreadActor.prototype); + +update(ChromeDebuggerActor.prototype, { + constructor: ChromeDebuggerActor, + + // A constant prefix that will be used to form the actor ID by the server. + actorPrefix: "chromeDebugger", + + /** + * Override the eligibility check for scripts and sources to make sure every + * script and source with a URL is stored when debugging chrome. + */ + _allowSource: function(aSourceURL) !!aSourceURL, + + /** + * An object that will be used by ThreadActors to tailor their behavior + * depending on the debugging context being required (chrome or content). + * The methods that this object provides must be bound to the ThreadActor + * before use. + */ + globalManager: { + findGlobals: function CDA_findGlobals() { + // Add every global known to the debugger as debuggee. + this.dbg.addAllGlobalsAsDebuggees(); + }, + + /** + * A function that the engine calls when a new global object has been + * created. + * + * @param aGlobal Debugger.Object + * The new global object that was created. + */ + onNewGlobal: function CDA_onNewGlobal(aGlobal) { + this.addDebuggee(aGlobal); + // Notify the client. + this.conn.send({ + from: this.actorID, + type: "newGlobal", + // TODO: after bug 801084 lands see if we need to JSONify this. + hostAnnotations: aGlobal.hostAnnotations + }); + } + } +}); + + +/** + * Manages the sources for a thread. Handles source maps, locations in the + * sources, etc for ThreadActors. + */ +function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate, + aOnNewSource) { + this._thread = aThreadActor; + this._useSourceMaps = aUseSourceMaps; + this._allow = aAllowPredicate; + this._onNewSource = aOnNewSource; + + // source map URL --> promise of SourceMapConsumer + this._sourceMaps = Object.create(null); + // generated source url --> promise of SourceMapConsumer + this._sourceMapsByGeneratedSource = Object.create(null); + // original source url --> promise of SourceMapConsumer + this._sourceMapsByOriginalSource = Object.create(null); + // source url --> SourceActor + this._sourceActors = Object.create(null); + // original url --> generated url + this._generatedUrlsByOriginalUrl = Object.create(null); +} + +/** + * Must be a class property because it needs to persist across reloads, same as + * the breakpoint store. + */ +ThreadSources._blackBoxedSources = new Set(); + +ThreadSources.prototype = { + /** + * Return the source actor representing |aURL|, creating one if none + * exists already. Returns null if |aURL| is not allowed by the 'allow' + * predicate. + * + * Right now this takes a URL, but in the future it should + * take a Debugger.Source. See bug 637572. + * + * @param String aURL + * The source URL. + * @param optional SourceMapConsumer aSourceMap + * The source map that introduced this source, if any. + * @returns a SourceActor representing the source at aURL or null. + */ + source: function TS_source(aURL, aSourceMap=null) { + if (!this._allow(aURL)) { + return null; + } + + if (aURL in this._sourceActors) { + return this._sourceActors[aURL]; + } + + let actor = new SourceActor(aURL, this._thread, aSourceMap); + this._thread.threadLifetimePool.addActor(actor); + this._sourceActors[aURL] = actor; + try { + this._onNewSource(actor); + } catch (e) { + reportError(e); + } + return actor; + }, + + /** + * Return a promise of an array of source actors representing all the + * sources of |aScript|. + * + * If source map handling is enabled and |aScript| has a source map, then + * use it to find all of |aScript|'s *original* sources; return a promise + * of an array of source actors for those. + */ + sourcesForScript: function TS_sourcesForScript(aScript) { + if (!this._useSourceMaps || !aScript.sourceMapURL) { + return resolve([this.source(aScript.url)].filter(isNotNull)); + } + + return this.sourceMap(aScript) + .then((aSourceMap) => { + return [ + this.source(s, aSourceMap) for (s of aSourceMap.sources) + ]; + }) + .then(null, (e) => { + reportError(e); + delete this._sourceMaps[this._normalize(aScript.sourceMapURL, aScript.url)]; + delete this._sourceMapsByGeneratedSource[aScript.url]; + return [this.source(aScript.url)]; + }) + .then(function (aSources) { + return aSources.filter(isNotNull); + }); + }, + + /** + * Return a promise of a SourceMapConsumer for the source map for + * |aScript|; if we already have such a promise extant, return that. + * |aScript| must have a non-null sourceMapURL. + */ + sourceMap: function TS_sourceMap(aScript) { + if (aScript.url in this._sourceMapsByGeneratedSource) { + return this._sourceMapsByGeneratedSource[aScript.url]; + } + dbg_assert(aScript.sourceMapURL); + let sourceMapURL = this._normalize(aScript.sourceMapURL, aScript.url); + let map = this._fetchSourceMap(sourceMapURL) + .then((aSourceMap) => { + for (let s of aSourceMap.sources) { + this._generatedUrlsByOriginalUrl[s] = aScript.url; + this._sourceMapsByOriginalSource[s] = resolve(aSourceMap); + } + return aSourceMap; + }); + this._sourceMapsByGeneratedSource[aScript.url] = map; + return map; + }, + + /** + * Return a promise of a SourceMapConsumer for the source map located at + * |aAbsSourceMapURL|, which must be absolute. If there is already such a + * promise extant, return it. + */ + _fetchSourceMap: function TS__fetchSourceMap(aAbsSourceMapURL) { + if (aAbsSourceMapURL in this._sourceMaps) { + return this._sourceMaps[aAbsSourceMapURL]; + } else { + let promise = fetch(aAbsSourceMapURL).then((rawSourceMap) => { + let map = new SourceMapConsumer(rawSourceMap); + let base = aAbsSourceMapURL.replace(/\/[^\/]+$/, '/'); + if (base.indexOf("data:") !== 0) { + map.sourceRoot = map.sourceRoot + ? this._normalize(map.sourceRoot, base) + : base; + } + return map; + }); + this._sourceMaps[aAbsSourceMapURL] = promise; + return promise; + } + }, + + /** + * Returns a promise of the location in the original source if the source is + * source mapped, otherwise a promise of the same location. + * + * TODO bug 637572: take/return a column + */ + getOriginalLocation: function TS_getOriginalLocation(aSourceUrl, aLine) { + if (aSourceUrl in this._sourceMapsByGeneratedSource) { + return this._sourceMapsByGeneratedSource[aSourceUrl] + .then(function (aSourceMap) { + let { source, line } = aSourceMap.originalPositionFor({ + source: aSourceUrl, + line: aLine, + column: Infinity + }); + return { + url: source, + line: line + }; + }); + } + + // No source map + return resolve({ + url: aSourceUrl, + line: aLine + }); + }, + + /** + * Returns a promise of the location in the generated source corresponding to + * the original source and line given. + * + * When we pass a script S representing generated code to |sourceMap|, + * above, that returns a promise P. The process of resolving P populates + * the tables this function uses; thus, it won't know that S's original + * source URLs map to S until P is resolved. + * + * TODO bug 637572: take/return a column + */ + getGeneratedLocation: function TS_getGeneratedLocation(aSourceUrl, aLine) { + if (aSourceUrl in this._sourceMapsByOriginalSource) { + return this._sourceMapsByOriginalSource[aSourceUrl] + .then((aSourceMap) => { + let { line } = aSourceMap.generatedPositionFor({ + source: aSourceUrl, + line: aLine, + column: Infinity + }); + return { + url: this._generatedUrlsByOriginalUrl[aSourceUrl], + line: line + }; + }); + } + + // No source map + return resolve({ + url: aSourceUrl, + line: aLine + }); + }, + + /** + * Returns true if URL for the given source is black boxed. + * + * @param aURL String + * The URL of the source which we are checking whether it is black + * boxed or not. + */ + isBlackBoxed: function TS_isBlackBoxed(aURL) { + return ThreadSources._blackBoxedSources.has(aURL); + }, + + /** + * Add the given source URL to the set of sources that are black boxed. If the + * thread is currently paused and we are black boxing the yougest frame's + * source, this will force a step. + * + * @param aURL String + * The URL of the source which we are black boxing. + */ + blackBox: function TS_blackBox(aURL) { + ThreadSources._blackBoxedSources.add(aURL); + }, + + /** + * Remove the given source URL to the set of sources that are black boxed. + * + * @param aURL String + * The URL of the source which we are no longer black boxing. + */ + unblackBox: function TS_unblackBox(aURL) { + ThreadSources._blackBoxedSources.delete(aURL); + }, + + /** + * Normalize multiple relative paths towards the base paths on the right. + */ + _normalize: function TS__normalize(...aURLs) { + dbg_assert(aURLs.length > 1); + let base = Services.io.newURI(aURLs.pop(), null, null); + let url; + while ((url = aURLs.pop())) { + base = Services.io.newURI(url, null, base); + } + return base.spec; + }, + + iter: function TS_iter() { + for (let url in this._sourceActors) { + yield this._sourceActors[url]; + } + } +}; + +// Utility functions. + +/** + * Utility function for updating an object with the properties of another + * object. + * + * @param aTarget Object + * The object being updated. + * @param aNewAttrs Object + * The new attributes being set on the target. + */ +function update(aTarget, aNewAttrs) { + for (let key in aNewAttrs) { + let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key); + + if (desc) { + Object.defineProperty(aTarget, key, desc); + } + } +} + +/** + * Returns true if its argument is not null. + */ +function isNotNull(aThing) { + return aThing !== null; +} + +/** + * Performs a request to load the desired URL and returns a promise. + * + * @param aURL String + * The URL we will request. + * @returns Promise + * A promise of the document at that URL, as a string. + * + * XXX: It may be better to use nsITraceableChannel to get to the sources + * without relying on caching when we can (not for eval, etc.): + * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ + */ +function fetch(aURL, aOptions={ loadFromCache: true }) { + let deferred = defer(); + let scheme; + let url = aURL.split(" -> ").pop(); + let charset; + let filePath = url; + // try { + // scheme = Services.io.extractScheme(url); + // } catch (e) { + // In the xpcshell tests, the script url is the absolute path of the test + // file, which will make a malformed URI error be thrown. Add the file + // scheme prefix ourselves. + url = "file://" + url; + // scheme = Services.io.extractScheme(url); + // } + scheme = "file"; + + switch (scheme) { + case "file": + case "chrome": + case "resource": + try { + // NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) { + // if (!Components.isSuccessCode(aStatus)) { + // deferred.reject("Request failed: " + url); + // return; + // } + let cc = globalDebuggee.cc; + let fileUtils = cc.FileUtils.getInstance(); + let source = fileUtils.getStringFromFile(filePath);//NetUtil.readInputStreamToString(aStream, aStream.available()); + if (!source) + { + deferred.reject("Request failed: " + url); + } + else + { + deferred.resolve(source); + } + // aStream.close(); + // }); + } catch (ex) { + deferred.reject("Request failed: " + url); + } + break; + + default: + let channel; + try { + channel = Services.io.newChannel(url, null, null); + } catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") { + // On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but + // newChannel won't be able to handle it. + url = "file:///" + url; + channel = Services.io.newChannel(url, null, null); + } + let chunks = []; + let streamListener = { + onStartRequest: function(aRequest, aContext, aStatusCode) { + if (!Components.isSuccessCode(aStatusCode)) { + deferred.reject("Request failed: " + url); + } + }, + onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) { + chunks.push(NetUtil.readInputStreamToString(aStream, aCount)); + }, + onStopRequest: function(aRequest, aContext, aStatusCode) { + if (!Components.isSuccessCode(aStatusCode)) { + deferred.reject("Request failed: " + url); + return; + } + + charset = channel.contentCharset; + deferred.resolve(chunks.join("")); + } + }; + + channel.loadFlags = aOptions.loadFromCache + ? channel.LOAD_FROM_CACHE + : channel.LOAD_BYPASS_CACHE; + channel.asyncOpen(streamListener, null); + break; + } + + return deferred.promise.then(function (source) { + return convertToUnicode(source, charset); + }); +} + +/** + * Convert a given string, encoded in a given character set, to unicode. + * + * @param string aString + * A string. + * @param string aCharset + * A character set. + */ +function convertToUnicode(aString, aCharset=null) { + // Decoding primitives. + // let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + // .createInstance(Ci.nsIScriptableUnicodeConverter); + // try { + // converter.charset = aCharset || "UTF-8"; + // return converter.ConvertToUnicode(aString); + // } catch(e) { + return aString; + // } +} + +/** + * Report the given error in the error console and to stdout. + */ +function reportError(aError) { + // Cu.reportError(aError); + dumpn(aError.message + ":\n" + aError.stack); +} diff --git a/cocos/scripting/javascript/bindings/js/debugger/core/promise.js b/cocos/scripting/javascript/bindings/js/debugger/core/promise.js new file mode 100644 index 0000000000..a695f5a3ad --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/core/promise.js @@ -0,0 +1,294 @@ +/* vim:set ts=2 sw=2 sts=2 expandtab */ +/*jshint undef: true es5: true node: true browser: true devel: true + forin: true latedef: false */ +/*global define: true, Cu: true, __URI__: true */ +//;(function(id, factory) { // Module boilerplate :( +// if (typeof(define) === 'function') { // RequireJS +// define(factory); +// } else if (typeof(require) === 'function') { // CommonJS +// factory.call(this, require, exports, module); +// } else if (String(this).indexOf('BackstagePass') >= 0) { // JSM +// this[factory.name] = {}; +// try { +// this.console = this['Components'].utils +// .import('resource://gre/modules/devtools/Console.jsm', {}).console; +// } +// catch (ex) { +// // Avoid failures on different toolkit configurations. +// } +// factory(function require(uri) { +// var imports = {}; +// this['Components'].utils.import(uri, imports); +// return imports; +// }, this[factory.name], { uri: __URI__, id: id }); +// this.EXPORTED_SYMBOLS = [factory.name]; +// } else { // Browser or alike +// var globals = this; +// factory(function require(id) { +// return globals[id]; +// }, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id }); +// } +//}).call(this, 'promise/core', function Promise(require, exports, module) { + +'use strict'; + +var exports = exports || {}; + +//module.metadata = { +// "stability": "unstable" +//}; + +/** + * Internal utility: Wraps given `value` into simplified promise, successfully + * fulfilled to a given `value`. Note the result is not a complete promise + * implementation, as its method `then` does not returns anything. + */ +function fulfilled(value) { + return { then: function then(fulfill) { fulfill(value); } }; +} + +/** + * Internal utility: Wraps given input into simplified promise, pre-rejected + * with a given `reason`. Note the result is not a complete promise + * implementation, as its method `then` does not returns anything. + */ +function rejected(reason) { + return { then: function then(fulfill, reject) { reject(reason); } }; +} + +/** + * Internal utility: Returns `true` if given `value` is a promise. Value is + * assumed to be a promise if it implements method `then`. + */ +function isPromise(value) { + return value && typeof(value.then) === 'function'; +} + +/** + * Creates deferred object containing fresh promise & methods to either resolve + * or reject it. The result is an object with the following properties: + * - `promise` Eventual value representation implementing CommonJS [Promises/A] + * (http://wiki.commonjs.org/wiki/Promises/A) API. + * - `resolve` Single shot function that resolves enclosed `promise` with a + * given `value`. + * - `reject` Single shot function that rejects enclosed `promise` with a given + * `reason`. + * + * An optional `prototype` argument is used as a prototype of the returned + * `promise` allowing one to implement additional API. If prototype is not + * passed then it falls back to `Object.prototype`. + * + * ## Example + * + * function fetchURI(uri, type) { + * var deferred = defer(); + * var request = new XMLHttpRequest(); + * request.open("GET", uri, true); + * request.responseType = type; + * request.onload = function onload() { + * deferred.resolve(request.response); + * } + * request.onerror = function(event) { + * deferred.reject(event); + * } + * request.send(); + * + * return deferred.promise; + * } + */ +function defer(prototype) { + // Define FIFO queue of observer pairs. Once promise is resolved & all queued + // observers are forwarded to `result` and variable is set to `null`. + var observers = []; + + // Promise `result`, which will be assigned a resolution value once promise + // is resolved. Note that result will always be assigned promise (or alike) + // object to take care of propagation through promise chains. If result is + // `null` promise is not resolved yet. + var result = null; + + prototype = (prototype || prototype === null) ? prototype : Object.prototype; + + // Create an object implementing promise API. + var promise = Object.create(prototype, { + then: { value: function then(onFulfill, onError) { + var deferred = defer(prototype); + + function resolve(value) { + // If `onFulfill` handler is provided resolve `deferred.promise` with + // result of invoking it with a resolution value. If handler is not + // provided propagate value through. + try { + deferred.resolve(onFulfill ? onFulfill(value) : value); + } + // `onFulfill` may throw exception in which case resulting promise + // is rejected with thrown exception. + catch(error) { + if (exports._reportErrors && typeof(console) === 'object') + console.error(error); + // Note: Following is equivalent of `deferred.reject(error)`, + // we use this shortcut to reduce a stack. + deferred.resolve(rejected(error)); + } + } + + function reject(reason) { + try { + if (onError) deferred.resolve(onError(reason)); + else deferred.resolve(rejected(reason)); + } + catch(error) { + if (exports._reportErrors && typeof(console) === 'object') + console.error(error); + deferred.resolve(rejected(error)); + } + } + + // If enclosed promise (`this.promise`) observers queue is still alive + // enqueue a new observer pair into it. Note that this does not + // necessary means that promise is pending, it may already be resolved, + // but we still have to queue observers to guarantee an order of + // propagation. + if (observers) { + observers.push({ resolve: resolve, reject: reject }); + } + // Otherwise just forward observer pair right to a `result` promise. + else { + result.then(resolve, reject); + } + + return deferred.promise; + }} + }) + + var deferred = { + promise: promise, + /** + * Resolves associated `promise` to a given `value`, unless it's already + * resolved or rejected. Note that resolved promise is not necessary a + * successfully fulfilled. Promise may be resolved with a promise `value` + * in which case `value` promise's fulfillment / rejection will propagate + * up to a promise resolved with `value`. + */ + resolve: function resolve(value) { + if (!result) { + // Store resolution `value` in a `result` as a promise, so that all + // the subsequent handlers can be simply forwarded to it. Since + // `result` will be a promise all the value / error propagation will + // be uniformly taken care of. + result = isPromise(value) ? value : fulfilled(value); + + // Forward already registered observers to a `result` promise in the + // order they were registered. Note that we intentionally dequeue + // observer at a time until queue is exhausted. This makes sure that + // handlers registered as side effect of observer forwarding are + // queued instead of being invoked immediately, guaranteeing FIFO + // order. + while (observers.length) { + var observer = observers.shift(); + result.then(observer.resolve, observer.reject); + } + + // Once `observers` queue is exhausted we `null`-ify it, so that + // new handlers are forwarded straight to the `result`. + observers = null; + } + }, + /** + * Rejects associated `promise` with a given `reason`, unless it's already + * resolved / rejected. This is just a (better performing) convenience + * shortcut for `deferred.resolve(reject(reason))`. + */ + reject: function reject(reason) { + // Note that if promise is resolved that does not necessary means that it + // is successfully fulfilled. Resolution value may be a promise in which + // case its result propagates. In other words if promise `a` is resolved + // with promise `b`, `a` is either fulfilled or rejected depending + // on weather `b` is fulfilled or rejected. Here `deferred.promise` is + // resolved with a promise pre-rejected with a given `reason`, there for + // `deferred.promise` is rejected with a given `reason`. This may feel + // little awkward first, but doing it this way greatly simplifies + // propagation through promise chains. + deferred.resolve(rejected(reason)); + } + }; + + return deferred; +} +exports.defer = defer; + +/** + * Returns a promise resolved to a given `value`. Optionally a second + * `prototype` argument may be provided to be used as a prototype for the + * returned promise. + */ +function resolve(value, prototype) { + var deferred = defer(prototype); + deferred.resolve(value); + return deferred.promise; +} +exports.resolve = resolve; + +/** + * Returns a promise rejected with a given `reason`. Optionally a second + * `prototype` argument may be provided to be used as a prototype for the + * returned promise. + */ +function reject(reason, prototype) { + var deferred = defer(prototype); + deferred.reject(reason); + return deferred.promise; +} +exports.reject = reject; + +var promised = (function() { + // Note: Define shortcuts and utility functions here in order to avoid + // slower property accesses and unnecessary closure creations on each + // call of this popular function. + + var call = Function.call; + var concat = Array.prototype.concat; + + // Utility function that does following: + // execute([ f, self, args...]) => f.apply(self, args) + function execute(args) { return call.apply(call, args) } + + // Utility function that takes promise of `a` array and maybe promise `b` + // as arguments and returns promise for `a.concat(b)`. + function promisedConcat(promises, unknown) { + return promises.then(function(values) { + return resolve(unknown).then(function(value) { + return values.concat([ value ]); + }); + }); + } + + return function promised(f, prototype) { + /** + Returns a wrapped `f`, which when called returns a promise that resolves to + `f(...)` passing all the given arguments to it, which by the way may be + promises. Optionally second `prototype` argument may be provided to be used + a prototype for a returned promise. + + ## Example + + var promise = promised(Array)(1, promise(2), promise(3)) + promise.then(console.log) // => [ 1, 2, 3 ] + **/ + + return function promised() { + // create array of [ f, this, args... ] + return concat.apply([ f, this ], arguments). + // reduce it via `promisedConcat` to get promised array of fulfillments + reduce(promisedConcat, resolve([], prototype)). + // finally map that to promise of `f.apply(this, args...)` + then(execute); + }; + } +})(); +exports.promised = promised; +// +var all = promised(Array); +exports.all = all; +// +//}); diff --git a/cocos/scripting/javascript/bindings/js/debugger/main.js b/cocos/scripting/javascript/bindings/js/debugger/main.js new file mode 100644 index 0000000000..f08009ade6 --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/main.js @@ -0,0 +1,928 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; +/** + * Toolkit glue for the remote debugging protocol, loaded into the + * debugging global. + */ + +//const Ci = Components.interfaces; +//const Cc = Components.classes; +//const CC = Components.Constructor; +//const Cu = Components.utils; +//const Cr = Components.results; +//const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties"; +// +//Cu.import("resource://gre/modules/Services.jsm"); +//Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +//let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log"); +// +//Cu.import("resource://gre/modules/jsdebugger.jsm"); +//addDebuggerToGlobal(this); +// +//Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); +//const { defer, resolve, reject, all } = Promise; +// +//Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); +// +//loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); + +let wantLogging = true; +let debuggerServer = null; + +function dumpn(str) { + if (wantLogging) { + log("DBG-SERVER: " + str + "\n"); + } +} + +function dbg_assert(cond, e) { + if (!cond) { + log("assert >>>> " + cond.toString()); + return e; + } +} + +function XPCInspector() { + this.exitNestedEventLoop = _exitNestedEventLoop; + this.enterNestedEventLoop = _enterNestedEventLoop; + this.eventLoopNestLevel = _getEventLoopNestLevel; +} + +//loadSubScript.call(this, "resource://gre/modules/devtools/server/transport.js"); + +// XPCOM constructors +// const ServerSocket = CC("@mozilla.org/network/server-socket;1", +// "nsIServerSocket", +// "initSpecialConnection"); + +function ServerSocket(aPort, flags, c){ + this.asyncListen = function(server){ + log("asyncListen...."); + debuggerServer = server; + }; +}; + +var gRegisteredModules = Object.create(null); + +/** + * The ModuleAPI object is passed to modules loaded using the + * DebuggerServer.registerModule() API. Modules can use this + * object to register actor factories. + * Factories registered through the module API will be removed + * when the module is unregistered or when the server is + * destroyed. + */ +function ModuleAPI() { + let activeTabActors = new Set(); + let activeGlobalActors = new Set(); + + return { + // See DebuggerServer.addGlobalActor for a description. + addGlobalActor: function(factory, name) { + DebuggerServer.addGlobalActor(factory, name); + activeGlobalActors.add(factory); + }, + // See DebuggerServer.removeGlobalActor for a description. + removeGlobalActor: function(factory) { + DebuggerServer.removeGlobalActor(factory); + activeGlobalActors.delete(factory); + }, + + // See DebuggerServer.addTabActor for a description. + addTabActor: function(factory, name) { + DebuggerServer.addTabActor(factory, name); + activeTabActors.add(factory); + }, + // See DebuggerServer.removeTabActor for a description. + removeTabActor: function(factory) { + DebuggerServer.removeTabActor(factory); + activeTabActors.delete(factory); + }, + + // Destroy the module API object, unregistering any + // factories registered by the module. + destroy: function() { + for (let factory of activeTabActors) { + DebuggerServer.removeTabActor(factory); + } + activeTabActors = null; + for (let factory of activeGlobalActors) { + DebuggerServer.removeGlobalActor(factory); + } + activeGlobalActors = null; + } + } +}; + +/*** + * Public API + */ +var DebuggerServer = { + _listener: null, + _initialized: false, + _transportInitialized: false, + xpcInspector: null, + _transport: null, + // Number of currently open TCP connections. + _socketConnections: 0, + // Map of global actor names to actor constructors provided by extensions. + globalActorFactories: {}, + // Map of tab actor names to actor constructors provided by extensions. + tabActorFactories: {}, + + LONG_STRING_LENGTH: 10000, + LONG_STRING_INITIAL_LENGTH: 1000, + LONG_STRING_READ_LENGTH: 1000, + + /** + * A handler function that prompts the user to accept or decline the incoming + * connection. + */ + _allowConnection: null, + + /** + * Prompt the user to accept or decline the incoming connection. This is the + * default implementation that products embedding the debugger server may + * choose to override. + * + * @return true if the connection should be permitted, false otherwise + */ + _defaultAllowConnection: function DS__defaultAllowConnection() { + // let title = L10N.getStr("remoteIncomingPromptTitle"); + // let msg = L10N.getStr("remoteIncomingPromptMessage"); + // let disableButton = L10N.getStr("remoteIncomingPromptDisable"); + // let prompt = Services.prompt; + // let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK + + // prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL + + // prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING + + // prompt.BUTTON_POS_1_DEFAULT; + // let result = prompt.confirmEx(null, title, msg, flags, null, null, + // disableButton, null, { value: false }); + // if (result == 0) { + // return true; + // } + // if (result == 2) { + // DebuggerServer.closeListener(true); + // Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false); + // } + // return false; + return true; + }, + + /** + * Initialize the debugger server. + * + * @param function aAllowConnectionCallback + * The embedder-provider callback, that decides whether an incoming + * remote protocol conection should be allowed or refused. + */ + init: function DS_init(aAllowConnectionCallback) { + if (this.initialized) { + return; + } + + this.xpcInspector = new XPCInspector();//Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); + this.initTransport(aAllowConnectionCallback); + this.addActors("resource://gre/modules/devtools/server/actors/root.js"); + + this._initialized = true; + }, + + /** + * Initialize the debugger server's transport variables. This can be + * in place of init() for cases where the jsdebugger isn't needed. + * + * @param function aAllowConnectionCallback + * The embedder-provider callback, that decides whether an incoming + * remote protocol conection should be allowed or refused. + */ + initTransport: function DS_initTransport(aAllowConnectionCallback) { + if (this._transportInitialized) { + return; + } + + this._connections = {}; + this._nextConnID = 0; + this._transportInitialized = true; + this._allowConnection = aAllowConnectionCallback ? + aAllowConnectionCallback : + this._defaultAllowConnection; + }, + + get initialized() this._initialized, + + /** + * Performs cleanup tasks before shutting down the debugger server, if no + * connections are currently open. Such tasks include clearing any actor + * constructors added at runtime. This method should be called whenever a + * debugger server is no longer useful, to avoid memory leaks. After this + * method returns, the debugger server must be initialized again before use. + */ + destroy: function DS_destroy() { + if (!this._initialized) { + return; + } + + for (let connID of Object.getOwnPropertyNames(this._connections)) { + this._connections[connID].close(); + } + + for (let id of Object.getOwnPropertyNames(gRegisteredModules)) { + let mod = gRegisteredModules[id]; + mod.module.unregister(mod.api); + } + gRegisteredModules = {}; + + this.closeListener(); + this.globalActorFactories = {}; + this.tabActorFactories = {}; + delete this._allowConnection; + this._transportInitialized = false; + this._initialized = false; + dumpn("Debugger server is shut down."); + }, + + /** + * Load a subscript into the debugging global. + * + * @param aURL string A url that will be loaded as a subscript into the + * debugging global. The user must load at least one script + * that implements a createRootActor() function to create the + * server's root actor. + */ + addActors: function DS_addActors(aURL) { + //loadSubScript.call(this, aURL); + }, + + /** + * Register a CommonJS module with the debugger server. + * @param id string + * The ID of a CommonJS module. This module must export + * 'register' and 'unregister' functions. + */ + registerModule: function(id) { + if (id in gRegisteredModules) { + throw new Error("Tried to register a module twice: " + id + "\n"); + } + + let moduleAPI = ModuleAPI(); + + let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); + let mod = devtools.require(id); + mod.register(moduleAPI); + gRegisteredModules[id] = { module: mod, api: moduleAPI }; + }, + + /** + * Returns true if a module id has been registered. + */ + isModuleRegistered: function(id) { + return (id in gRegisteredModules); + }, + + /** + * Unregister a previously-loaded CommonJS module from the debugger server. + */ + unregisterModule: function(id) { + let mod = gRegisteredModules[id]; + if (!mod) { + throw new Error("Tried to unregister a module that was not previously registered."); + } + mod.module.unregister(mod.api); + mod.api.destroy(); + delete gRegisteredModules[id]; + }, + + /** + * Install Firefox-specific actors. + */ + addBrowserActors: function DS_addBrowserActors() { + this.addActors("resource://gre/modules/devtools/server/actors/webbrowser.js"); + this.addActors("resource://gre/modules/devtools/server/actors/script.js"); + this.addGlobalActor(this.ChromeDebuggerActor, "chromeDebugger"); + this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js"); + this.addActors("resource://gre/modules/devtools/server/actors/gcli.js"); + if ("nsIProfiler" in Ci) + this.addActors("resource://gre/modules/devtools/server/actors/profiler.js"); + + this.addActors("resource://gre/modules/devtools/server/actors/styleeditor.js"); + this.addActors("resource://gre/modules/devtools/server/actors/webapps.js"); + this.registerModule("devtools/server/actors/inspector"); + }, + + /** + * Listens on the given port for remote debugger connections. + * + * @param aPort int + * The port to listen on. + */ + openListener: function DS_openListener(aPort) { + // if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) { + // return false; + // } + this._checkInit(); + + // Return early if the server is already listening. + if (this._listener) { + return true; + } + + // let flags = Ci.nsIServerSocket.KeepWhenOffline; + // A preference setting can force binding on the loopback interface. + // if (Services.prefs.getBoolPref("devtools.debugger.force-local")) { + // flags |= Ci.nsIServerSocket.LoopbackOnly; + // } + + let flags = 0; + + try { + let socket = new ServerSocket(aPort, flags, 4); + socket.asyncListen(this); + this._listener = socket; + } catch (e) { + dumpn("Could not start debugging listener on port " + aPort + ": " + e); + throw "Cr.NS_ERROR_NOT_AVAILABLE"; + } + this._socketConnections++; + + return true; + }, + + /** + * Close a previously-opened TCP listener. + * + * @param aForce boolean [optional] + * If set to true, then the socket will be closed, regardless of the + * number of open connections. + */ + closeListener: function DS_closeListener(aForce) { + if (!this._listener || this._socketConnections == 0) { + return false; + } + + // Only close the listener when the last connection is closed, or if the + // aForce flag is passed. + if (--this._socketConnections == 0 || aForce) { + this._listener.close(); + this._listener = null; + this._socketConnections = 0; + } + + return true; + }, + + /** + * Creates a new connection to the local debugger speaking over a fake + * transport. This connection results in straightforward calls to the onPacket + * handlers of each side. + * + * @returns a client-side DebuggerTransport for communicating with + * the newly-created connection. + */ + connectPipe: function DS_connectPipe() { + this._checkInit(); + + let serverTransport = new LocalDebuggerTransport; + let clientTransport = new LocalDebuggerTransport(serverTransport); + serverTransport.other = clientTransport; + let connection = this._onConnection(serverTransport); + + // I'm putting this here because I trust you. + // + // There are times, when using a local connection, when you're going + // to be tempted to just get direct access to the server. Resist that + // temptation! If you succumb to that temptation, you will make the + // fine developers that work on Fennec and Firefox OS sad. They're + // professionals, they'll try to act like they understand, but deep + // down you'll know that you hurt them. + // + // This reference allows you to give in to that temptation. There are + // times this makes sense: tests, for example, and while porting a + // previously local-only codebase to the remote protocol. + // + // But every time you use this, you will feel the shame of having + // used a property that starts with a '_'. + clientTransport._serverConnection = connection; + + return clientTransport; + }, + + + // nsIServerSocketListener implementation + + onSocketAccepted: + makeInfallible(function DS_onSocketAccepted(aSocket, aTransport) { + if (!this._allowConnection()) { + return; + } + dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port); + + let input = aTransport.openInputStream(0, 0, 0); + let output = aTransport.openOutputStream(0, 0, 0); + let transport = new DebuggerTransport(input, output); + DebuggerServer._onConnection(transport); + }, "DebuggerServer.onSocketAccepted"), + + onStopListening: function DS_onStopListening(aSocket, status) { + dumpn("onStopListening, status: " + status); + }, + + /** + * Raises an exception if the server has not been properly initialized. + */ + _checkInit: function DS_checkInit() { + if (!this._transportInitialized) { + throw "DebuggerServer has not been initialized."; + } + + if (!this.createRootActor) { + throw "Use DebuggerServer.addActors() to add a root actor implementation."; + } + }, + + /** + * Create a new debugger connection for the given transport. Called + * after connectPipe() or after an incoming socket connection. + */ + _onConnection: function DS_onConnection(aTransport) { + log("DebuggerServer._onConnection...."); + + this._transport = aTransport; + + let connID = "conn" + this._nextConnID++ + '.'; + let conn = new DebuggerServerConnection(connID, aTransport); + this._connections[connID] = conn; + + // Create a root actor for the connection and send the hello packet. + conn.rootActor = this.createRootActor(conn); + conn.addActor(conn.rootActor); + + aTransport.send(conn.rootActor.sayHello()); + aTransport.ready(); + + return conn; + }, + + /** + * Remove the connection from the debugging server. + */ + _connectionClosed: function DS_connectionClosed(aConnection) { + delete this._connections[aConnection.prefix]; + }, + + // DebuggerServer extension API. + + /** + * Registers handlers for new tab-scoped request types defined dynamically. + * This is used for example by add-ons to augment the functionality of the tab + * actor. Note that the name or actorPrefix of the request type is not allowed + * to clash with existing protocol packet properties, like 'title', 'url' or + * 'actor', since that would break the protocol. + * + * @param aFunction function + * The constructor function for this request type. This expects to be + * called as a constructor (i.e. with 'new'), and passed two + * arguments: the DebuggerServerConnection, and the BrowserTabActor + * with which it will be associated. + * + * @param aName string [optional] + * The name of the new request type. If this is not present, the + * actorPrefix property of the constructor prototype is used. + */ + addTabActor: function DS_addTabActor(aFunction, aName) { + let name = aName ? aName : aFunction.prototype.actorPrefix; + if (["title", "url", "actor"].indexOf(name) != -1) { + throw Error(name + " is not allowed"); + } + if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) { + throw Error(name + " already exists"); + } + DebuggerServer.tabActorFactories[name] = aFunction; + }, + + /** + * Unregisters the handler for the specified tab-scoped request type. + * This may be used for example by add-ons when shutting down or upgrading. + * + * @param aFunction function + * The constructor function for this request type. + */ + removeTabActor: function DS_removeTabActor(aFunction) { + for (let name in DebuggerServer.tabActorFactories) { + let handler = DebuggerServer.tabActorFactories[name]; + if (handler.name == aFunction.name) { + delete DebuggerServer.tabActorFactories[name]; + } + } + }, + + /** + * Registers handlers for new browser-scoped request types defined + * dynamically. This is used for example by add-ons to augment the + * functionality of the root actor. Note that the name or actorPrefix of the + * request type is not allowed to clash with existing protocol packet + * properties, like 'from', 'tabs' or 'selected', since that would break the + * protocol. + * + * @param aFunction function + * The constructor function for this request type. This expects to be + * called as a constructor (i.e. with 'new'), and passed two + * arguments: the DebuggerServerConnection, and the BrowserRootActor + * with which it will be associated. + * + * @param aName string [optional] + * The name of the new request type. If this is not present, the + * actorPrefix property of the constructor prototype is used. + */ + addGlobalActor: function DS_addGlobalActor(aFunction, aName) { + let name = aName ? aName : aFunction.prototype.actorPrefix; + if (["from", "tabs", "selected"].indexOf(name) != -1) { + throw Error(name + " is not allowed"); + } + if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) { + throw Error(name + " already exists"); + } + DebuggerServer.globalActorFactories[name] = aFunction; + }, + + /** + * Unregisters the handler for the specified browser-scoped request type. + * This may be used for example by add-ons when shutting down or upgrading. + * + * @param aFunction function + * The constructor function for this request type. + */ + removeGlobalActor: function DS_removeGlobalActor(aFunction) { + for (let name in DebuggerServer.globalActorFactories) { + let handler = DebuggerServer.globalActorFactories[name]; + if (handler.name == aFunction.name) { + delete DebuggerServer.globalActorFactories[name]; + } + } + } +}; + + +/** + * Construct an ActorPool. + * + * ActorPools are actorID -> actor mapping and storage. These are + * used to accumulate and quickly dispose of groups of actors that + * share a lifetime. + */ +function ActorPool(aConnection) +{ + this.conn = aConnection; + this._cleanups = {}; + this._actors = {}; +} + +ActorPool.prototype = { + /** + * Add an actor to the actor pool. If the actor doesn't have an ID, + * allocate one from the connection. + * + * @param aActor object + * The actor implementation. If the object has a + * 'disconnect' property, it will be called when the actor + * pool is cleaned up. + */ + addActor: function AP_addActor(aActor) { + aActor.conn = this.conn; + if (!aActor.actorID) { + let prefix = aActor.actorPrefix; + if (typeof aActor == "function") { + prefix = aActor.prototype.actorPrefix; + } + aActor.actorID = this.conn.allocID(prefix || undefined); + } + + if (aActor.registeredPool) { + aActor.registeredPool.removeActor(aActor); + } + aActor.registeredPool = this; + + this._actors[aActor.actorID] = aActor; + if (aActor.disconnect) { + this._cleanups[aActor.actorID] = aActor; + } + }, + + get: function AP_get(aActorID) { + return this._actors[aActorID]; + }, + + has: function AP_has(aActorID) { + return aActorID in this._actors; + }, + + /** + * Returns true if the pool is empty. + */ + isEmpty: function AP_isEmpty() { + return Object.keys(this._actors).length == 0; + }, + + /** + * Remove an actor from the actor pool. + */ + removeActor: function AP_remove(aActor) { + delete this._actors[aActor.actorID]; + delete this._cleanups[aActor.actorID]; + }, + + /** + * Match the api expected by the protocol library. + */ + unmanage: function(aActor) { + return this.removeActor(aActor); + }, + + /** + * Run all actor cleanups. + */ + cleanup: function AP_cleanup() { + for each (let actor in this._cleanups) { + actor.disconnect(); + } + this._cleanups = {}; + } +} + +/** + * Creates a DebuggerServerConnection. + * + * Represents a connection to this debugging global from a client. + * Manages a set of actors and actor pools, allocates actor ids, and + * handles incoming requests. + * + * @param aPrefix string + * All actor IDs created by this connection should be prefixed + * with aPrefix. + * @param aTransport transport + * Packet transport for the debugging protocol. + */ +function DebuggerServerConnection(aPrefix, aTransport) +{ + this._prefix = aPrefix; + this._transport = aTransport; + this._transport.hooks = this; + this._nextID = 1; + + this._actorPool = new ActorPool(this); + this._extraPools = []; +} + +DebuggerServerConnection.prototype = { + _prefix: null, + get prefix() { return this._prefix }, + + _transport: null, + get transport() { return this._transport }, + + close: function() { + this._transport.close(); + }, + + send: function DSC_send(aPacket) { + this.transport.send(aPacket); + }, + + allocID: function DSC_allocID(aPrefix) { + return this.prefix + (aPrefix || '') + this._nextID++; + }, + + /** + * Add a map of actor IDs to the connection. + */ + addActorPool: function DSC_addActorPool(aActorPool) { + this._extraPools.push(aActorPool); + }, + + /** + * Remove a previously-added pool of actors to the connection. + * + * @param ActorPool aActorPool + * The ActorPool instance you want to remove. + * @param boolean aCleanup + * True if you want to disconnect each actor from the pool, false + * otherwise. + */ + removeActorPool: function DSC_removeActorPool(aActorPool, aCleanup) { + let index = this._extraPools.lastIndexOf(aActorPool); + if (index > -1) { + let pool = this._extraPools.splice(index, 1); + if (aCleanup) { + pool.map(function(p) { p.cleanup(); }); + } + } + }, + + /** + * Add an actor to the default actor pool for this connection. + */ + addActor: function DSC_addActor(aActor) { + this._actorPool.addActor(aActor); + }, + + /** + * Remove an actor to the default actor pool for this connection. + */ + removeActor: function DSC_removeActor(aActor) { + this._actorPool.removeActor(aActor); + }, + + /** + * Match the api expected by the protocol library. + */ + unmanage: function(aActor) { + return this.removeActor(aActor); + }, + + /** + * Look up an actor implementation for an actorID. Will search + * all the actor pools registered with the connection. + * + * @param aActorID string + * Actor ID to look up. + */ + getActor: function DSC_getActor(aActorID) { + let pool = this.poolFor(aActorID); + if (pool) { + return pool.get(aActorID); + } + + if (aActorID === "root") { + return this.rootActor; + } + + return null; + }, + + poolFor: function DSC_actorPool(aActorID) { + if (this._actorPool && this._actorPool.has(aActorID)) { + return this._actorPool; + } + + for (let pool of this._extraPools) { + if (pool.has(aActorID)) { + return pool; + } + } + return null; + }, + + _unknownError: function DSC__unknownError(aPrefix, aError) { + let errorString = safeErrorString(aError); + errorString += "\n" + aError.stack; + // Cu.reportError(errorString); + dumpn(errorString); + return { + error: "unknownError", + message: (aPrefix + "': " + errorString) + }; + }, + + // Transport hooks. + + /** + * Called by DebuggerTransport to dispatch incoming packets as appropriate. + * + * @param aPacket object + * The incoming packet. + */ + onPacket: function DSC_onPacket(aPacket) { + let actor = this.getActor(aPacket.to); + if (!actor) { + this.transport.send({ from: aPacket.to ? aPacket.to : "root", + error: "noSuchActor" }); + return; + } + + // Dyamically-loaded actors have to be created lazily. + if (typeof actor == "function") { + let instance; + try { + instance = new actor(); + } catch (e) { + this.transport.send(this._unknownError( + "Error occurred while creating actor '" + actor.name, + e)); + } + instance.parentID = actor.parentID; + // We want the newly-constructed actor to completely replace the factory + // actor. Reusing the existing actor ID will make sure ActorPool.addActor + // does the right thing. + instance.actorID = actor.actorID; + actor.registeredPool.addActor(instance); + actor = instance; + } + + var ret = null; + // log("actor.requestTypes: "+actor.requestTypes+", cb: "+actor.requestTypes[aPacket.type]); + // Dispatch the request to the actor. + if (actor.requestTypes && actor.requestTypes[aPacket.type]) { + try { + this.currentPacket = aPacket; + ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket, this); + } catch(e) { + this.transport.send(this._unknownError( + "error occurred while processing '" + aPacket.type, + e)); + } finally { + delete this.currentPacket; + } + } else { + ret = { error: "unrecognizedPacketType", + message: ('Actor "' + actor.actorID + + '" does not recognize the packet type "' + + aPacket.type + '"') }; + } + + if (!ret) { + // This should become an error once we've converted every user + // of this to promises in bug 794078. + return; + } + + resolve(ret) + .then(null, (e) => { + return this._unknownError( + "error occurred while processing '" + aPacket.type, + e); + }) + .then(function (aResponse) { + if (!aResponse.from) { + aResponse.from = aPacket.to; + } + return aResponse; + }) + .then(this.transport.send.bind(this.transport)); + }, + + /** + * Called by DebuggerTransport when the underlying stream is closed. + * + * @param aStatus nsresult + * The status code that corresponds to the reason for closing + * the stream. + */ + onClosed: function DSC_onClosed(aStatus) { + dumpn("Cleaning up connection."); + + this._actorPool.cleanup(); + this._actorPool = null; + this._extraPools.map(function(p) { p.cleanup(); }); + this._extraPools = null; + + DebuggerServer._connectionClosed(this); + }, + + /* + * Debugging helper for inspecting the state of the actor pools. + */ + _dumpPools: function DSC_dumpPools() { + dumpn("/-------------------- dumping pools:"); + if (this._actorPool) { + dumpn("--------------------- actorPool actors: " + + uneval(Object.keys(this._actorPool._actors))); + } + for each (let pool in this._extraPools) + dumpn("--------------------- extraPool actors: " + + uneval(Object.keys(pool._actors))); + }, + + /* + * Debugging helper for inspecting the state of an actor pool. + */ + _dumpPool: function DSC_dumpPools(aPool) { + dumpn("/-------------------- dumping pool:"); + dumpn("--------------------- actorPool actors: " + + uneval(Object.keys(aPool._actors))); + } +}; + +/** + * Localization convenience methods. + */ +// let L10N = { + +// /** +// * L10N shortcut function. +// * +// * @param string aName +// * @return string +// */ +// getStr: function L10N_getStr(aName) { +// return this.stringBundle.GetStringFromName(aName); +// } +// }; + +// XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() { +// return Services.strings.createBundle(DBG_STRINGS_URI); +// }); diff --git a/cocos/scripting/javascript/bindings/js/debugger/transport.js b/cocos/scripting/javascript/bindings/js/debugger/transport.js new file mode 100644 index 0000000000..8676e367a8 --- /dev/null +++ b/cocos/scripting/javascript/bindings/js/debugger/transport.js @@ -0,0 +1,288 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; +// Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +/** + * An adapter that handles data transfers between the debugger client and + * server. It can work with both nsIPipe and nsIServerSocket transports so + * long as the properly created input and output streams are specified. + * + * @param aInput nsIInputStream + * The input stream. + * @param aOutput nsIAsyncOutputStream + * The output stream. + * + * Given a DebuggerTransport instance dt: + * 1) Set dt.hooks to a packet handler object (described below). + * 2) Call dt.ready() to begin watching for input packets. + * 3) Send packets as you please, and handle incoming packets passed to + * hook.onPacket. + * 4) Call dt.close() to close the connection, and disengage from the event + * loop. + * + * A packet handler object is an object with two methods: + * + * - onPacket(packet) - called when we have received a complete packet. + * |Packet| is the parsed form of the packet --- a JavaScript value, not + * a JSON-syntax string. + * + * - onClosed(status) - called when the connection is closed. |Status| is + * an nsresult, of the sort passed to nsIRequestObserver. + * + * Data is transferred as a JSON packet serialized into a string, with the + * string length prepended to the packet, followed by a colon + * ([length]:[packet]). The contents of the JSON packet are specified in + * the Remote Debugging Protocol specification. + */ +this.DebuggerTransport = function DebuggerTransport(aInput, aOutput) +{ + this._input = aInput; + this._output = aOutput; + + this._converter = null;//Cc["@mozilla.org/intl/scriptableunicodeconverter"] + // .createInstance(Ci.nsIScriptableUnicodeConverter); + // this._converter.charset = "UTF-8"; + + this._outgoing = ""; + this._incoming = ""; + + this.hooks = null; +} + +DebuggerTransport.prototype = { + /** + * Transmit a packet. + * + * This method returns immediately, without waiting for the entire + * packet to be transmitted, registering event handlers as needed to + * transmit the entire packet. Packets are transmitted in the order + * they are passed to this method. + */ + send: function DT_send(aPacket) { + // TODO (bug 709088): remove pretty printing when the protocol is done. + let data = JSON.stringify(aPacket, null, 2); + // data = this._converter.ConvertFromUnicode(data); + + let data_for_len = utf16to8(data); + + this._outgoing = data_for_len.length + ':' + data; + + this._flushOutgoing(); + }, + + /** + * Close the transport. + */ + close: function DT_close() { + this._input.close(); + this._output.close(); + }, + + /** + * Flush the outgoing stream. + */ + _flushOutgoing: function DT_flushOutgoing() { + if (this._outgoing.length > 0) { + // var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(); + // this._output.asyncWait(this, 0, 0, threadManager.currentThread); + log("outgoing: " + this._outgoing);//.substring(0, 200)); + _bufferWrite(this._outgoing); + } + }, + + onOutputStreamReady: + makeInfallible(function DT_onOutputStreamReady(aStream) { + let written = 0; + try { + written = aStream.write(this._outgoing, this._outgoing.length); + } catch(e if e.result == Components.results.NS_BASE_STREAM_CLOSED) { + dumpn("Connection closed."); + this.close(); + return; + } + this._outgoing = this._outgoing.slice(written); + this._flushOutgoing(); + }, "DebuggerTransport.prototype.onOutputStreamReady"), + + /** + * Initialize the input stream for reading. Once this method has been + * called, we watch for packets on the input stream, and pass them to + * this.hook.onPacket. + */ + ready: function DT_ready() { + // let pump = Cc["@mozilla.org/network/input-stream-pump;1"] + // .createInstance(Ci.nsIInputStreamPump); + // pump.init(this._input, -1, -1, 0, 0, false); + // pump.asyncRead(this, null); + }, + + // nsIStreamListener + onStartRequest: + makeInfallible(function DT_onStartRequest(aRequest, aContext) {}, + "DebuggerTransport.prototype.onStartRequest"), + + onStopRequest: + makeInfallible(function DT_onStopRequest(aRequest, aContext, aStatus) { + this.close(); + if (this.hooks) { + this.hooks.onClosed(aStatus); + this.hooks = null; + } + }, "DebuggerTransport.prototype.onStopRequest"), + + onDataAvailable: makeInfallible(function DT_onDataAvailable (incoming) +// makeInfallible(function DT_onDataAvailable(aRequest, aContext, +// aStream, aOffset, aCount) + { + this._incoming = incoming;//+= NetUtil.readInputStreamToString(aStream, + // aStream.available()); + while (this._processIncoming()) {}; + }, "DebuggerTransport.prototype.onDataAvailable"), + + /** + * Process incoming packets. Returns true if a packet has been received, either + * if it was properly parsed or not. Returns false if the incoming stream does + * not contain a full packet yet. After a proper packet is parsed, the dispatch + * handler DebuggerTransport.hooks.onPacket is called with the packet as a + * parameter. + */ + _processIncoming: function DT__processIncoming() { + // Well this is ugly. + let sep = this._incoming.indexOf(':'); + if (sep < 0) { + return false; + } + + let count = parseInt(this._incoming.substring(0, sep)); + if (this._incoming.length - (sep + 1) < count) { + // Don't have a complete request yet. + return false; + } + + // We have a complete request, pluck it out of the data and parse it. + this._incoming = this._incoming.substring(sep + 1); + let packet = this._incoming.substring(0, count); + this._incoming = this._incoming.substring(count); + + try { + // packet = this._converter.ConvertToUnicode(packet); + packet = utf8to16(packet); + var parsed = JSON.parse(packet); + } catch(e) { + let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")"; + // if (Cu.reportError) { + // Cu.reportError(msg); + // } + dump(msg + "\n"); + return true; + } + + dumpn("Got: " + packet); + let self = this; + + // Services.tm.currentThread.dispatch(makeInfallible(function() { + self.hooks.onPacket(parsed); + // }, "DebuggerTransport instance's this.hooks.onPacket"), 0); + + return true; + } +} + + +/** + * An adapter that handles data transfers between the debugger client and + * server when they both run in the same process. It presents the same API as + * DebuggerTransport, but instead of transmitting serialized messages across a + * connection it merely calls the packet dispatcher of the other side. + * + * @param aOther LocalDebuggerTransport + * The other endpoint for this debugger connection. + * + * @see DebuggerTransport + */ +this.LocalDebuggerTransport = function LocalDebuggerTransport(aOther) +{ + this.other = aOther; + this.hooks = null; + + /* + * A packet number, shared between this and this.other. This isn't used + * by the protocol at all, but it makes the packet traces a lot easier to + * follow. + */ + this._serial = this.other ? this.other._serial : { count: 0 }; +} + +LocalDebuggerTransport.prototype = { + /** + * Transmit a message by directly calling the onPacket handler of the other + * endpoint. + */ + send: function LDT_send(aPacket) { + let serial = this._serial.count++; + if (wantLogging) { + if (aPacket.to) { + dumpn("Packet " + serial + " sent to " + uneval(aPacket.to)); + } else if (aPacket.from) { + dumpn("Packet " + serial + " sent from " + uneval(aPacket.from)); + } + } + this._deepFreeze(aPacket); + let other = this.other; + if (other) { + Services.tm.currentThread.dispatch(makeInfallible(function() { + // Avoid the cost of JSON.stringify() when logging is disabled. + if (wantLogging) { + dumpn("Received packet " + serial + ": " + JSON.stringify(aPacket, null, 2)); + } + if (other.hooks) { + other.hooks.onPacket(aPacket); + } + }, "LocalDebuggerTransport instance's this.other.hooks.onPacket"), 0); + } + }, + + /** + * Close the transport. + */ + close: function LDT_close() { + if (this.other) { + // Remove the reference to the other endpoint before calling close(), to + // avoid infinite recursion. + let other = this.other; + delete this.other; + other.close(); + } + if (this.hooks) { + this.hooks.onClosed(); + this.hooks = null; + } + }, + + /** + * An empty method for emulating the DebuggerTransport API. + */ + ready: function LDT_ready() {}, + + /** + * Helper function that makes an object fully immutable. + */ + _deepFreeze: function LDT_deepFreeze(aObject) { + Object.freeze(aObject); + for (let prop in aObject) { + // Freeze the properties that are objects, not on the prototype, and not + // already frozen. Note that this might leave an unfrozen reference + // somewhere in the object if there is an already frozen object containing + // an unfrozen object. + if (aObject.hasOwnProperty(prop) && typeof aObject === "object" && + !Object.isFrozen(aObject)) { + this._deepFreeze(o[prop]); + } + } + } +}; From f3f24e3bbd9ad9ab1e8147b9cb6c5a1006c02ed4 Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 13:54:16 +0800 Subject: [PATCH 107/116] issue #2905:use - to connect multiple words --- docs/CODING_STYLE.md | 131 ++++++++++++++++++ docs/RELEASE_NOTES | 4 + .../AssetsManager.cpp | 0 .../AssetsManager.h | 0 .../CCPhysicsDebugNode.cpp | 0 .../CCPhysicsDebugNode.h | 0 .../CCPhysicsSprite.cpp | 0 .../CCPhysicsSprite.h | 0 8 files changed, 135 insertions(+) create mode 100644 docs/CODING_STYLE.md create mode 100644 docs/RELEASE_NOTES rename extensions/{AssetsManager => assets-manager}/AssetsManager.cpp (100%) rename extensions/{AssetsManager => assets-manager}/AssetsManager.h (100%) rename extensions/{physics_nodes => physics-nodes}/CCPhysicsDebugNode.cpp (100%) rename extensions/{physics_nodes => physics-nodes}/CCPhysicsDebugNode.h (100%) rename extensions/{physics_nodes => physics-nodes}/CCPhysicsSprite.cpp (100%) rename extensions/{physics_nodes => physics-nodes}/CCPhysicsSprite.h (100%) diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md new file mode 100644 index 0000000000..4b7bf2a7c8 --- /dev/null +++ b/docs/CODING_STYLE.md @@ -0,0 +1,131 @@ +# cocos2d-x C++ coding sytle + + +## Detailed information + +Please, refer to this document for a detailed version of the cocos2d-x C++ coding sytle: + +* [cocos2d-x c++ coding style](http://www.cocos2d-x.org/wiki/Cocos2d_c++_coding_style) + + +## Quick Sample + +Use this sample as a quick reference. But DO READ the detailed doc for more info. + +Header file: + +```c++ +/** + * We use Doxygen strings for documentation. + * All public classes, methods, structs should be documented using Doxygen Strings + */ +class CC_DLL Sprite : public NodeRGBA, public TextureProtocol +{ /* class braces start in a new line */ + +/* no indentation here for public, protected or private */ +/* First add all the "public" stuff, then all the "protected" stuff, and finally all the "private" stuff +public: + + /* we don't use tabs, we use spaces, and we use a 4 space identation */ + /* 1st add all static const */ + static const int INDEX_NOT_INITIALIZED = -1; + + /* then add all the creators and other relevant static methods */ + static Sprite* create(); + static Sprite* create(const char *filename); + static Sprite* create(const char *filename, const Rect& rect); + + /* if applicable, then add the consturctors / destructors */ + Sprite(); + virtual ~Sprite(void); + + /* then add all the initialization methods */ + /* notice that they are in the same order as the creators */ + virtual bool init(void); + virtual bool initWithTexture(Texture2D *texture); + virtual bool initWithTexture(Texture2D *texture, const Rect& rect); + + + + /* then add the regular instace methods */ + virtual void updateTransform(void); + virtual SpriteBatchNode* getBatchNode(void); + virtual void setBatchNode(SpriteBatchNode *spriteBatchNode); + + + /* then add all the overriden methods */ + /* notice that all overriden methods must use the 'override' keyword */ + /* overriden methods are not forced to have doxygen strings UNLESS they change the behavior in a non obvios way */ + virtual void setPosition(const Point& pos) override; + virtual void setRotation(float rotation) override; + virtual void setRotationX(float rotationX) override; + + + /* once you finish with the 'public' methods, start with the 'protected' ones */ +protected: + + /* protected methods are not forced to have Doxygen strings, but if they have it, better */ + void updateColor(void); + virtual void setTextureCoords(Rect rect); + + /* After adding all the methods, add the ivars */ + /* all ivars must start with _ */ + /* Do not use Hungarian notation */ + TextureAtlas* _textureAtlas; + int _atlasIndex; + SpriteBatchNode* _batchNode; +}; + +``` + +Implementation file: + +```c++ +/* Do not use doxygen comments on the implementation file */ + +/* The methos MUST be in the same order as where declared in the header file */ + +Sprite* Sprite::create(const char *filename) +{ + /* Don't use tabs. Use spaces. Use 4-space indentation */ + Sprite *sprite = new Sprite(); + + /* put curly braces in the same line as in the 'if'*/ + /* leave a space between the 'if' and the '(' */ + /* don't leave spaces between '()' */ + if (sprite && sprite->initWithFile(filename)) { + sprite->autorelease(); + return sprite; + } + CC_SAFE_DELETE(sprite); + return NULL; +} + +/* Initialization list can be indented to 0 spaces, or to 4 spaces. If in doubt, be consistent with the indentation already used in the file */ +/* Only use the Initialization lists for types that can't fail when initialized */ +Sprite::Sprite() +: _shouldBeHidden(false) +, _texture(nullptr) +, _physicsBody(nullptr) +{ +} + +/* use the 'initXXX' methods to initialize types that might fail */ +bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) +{ + /* it ok not use use curly braces */ + if (something) + do_something(); + else + something_else(); + + /* but if you use curly branches in one branch, all the branches should use curly branches */ + if (something) { + do_something1(); + do_something2(); + } else { + so_something_else(); + } +} + +``` diff --git a/docs/RELEASE_NOTES b/docs/RELEASE_NOTES new file mode 100644 index 0000000000..f10872da6c --- /dev/null +++ b/docs/RELEASE_NOTES @@ -0,0 +1,4 @@ +===== cocos2d-x 3.0 Release Notes ===== + +Please, read the online release notes document: +http://www.cocos2d-x.org/wiki/Release_Notes_for_Cocos2d-x_v300 \ No newline at end of file diff --git a/extensions/AssetsManager/AssetsManager.cpp b/extensions/assets-manager/AssetsManager.cpp similarity index 100% rename from extensions/AssetsManager/AssetsManager.cpp rename to extensions/assets-manager/AssetsManager.cpp diff --git a/extensions/AssetsManager/AssetsManager.h b/extensions/assets-manager/AssetsManager.h similarity index 100% rename from extensions/AssetsManager/AssetsManager.h rename to extensions/assets-manager/AssetsManager.h diff --git a/extensions/physics_nodes/CCPhysicsDebugNode.cpp b/extensions/physics-nodes/CCPhysicsDebugNode.cpp similarity index 100% rename from extensions/physics_nodes/CCPhysicsDebugNode.cpp rename to extensions/physics-nodes/CCPhysicsDebugNode.cpp diff --git a/extensions/physics_nodes/CCPhysicsDebugNode.h b/extensions/physics-nodes/CCPhysicsDebugNode.h similarity index 100% rename from extensions/physics_nodes/CCPhysicsDebugNode.h rename to extensions/physics-nodes/CCPhysicsDebugNode.h diff --git a/extensions/physics_nodes/CCPhysicsSprite.cpp b/extensions/physics-nodes/CCPhysicsSprite.cpp similarity index 100% rename from extensions/physics_nodes/CCPhysicsSprite.cpp rename to extensions/physics-nodes/CCPhysicsSprite.cpp diff --git a/extensions/physics_nodes/CCPhysicsSprite.h b/extensions/physics-nodes/CCPhysicsSprite.h similarity index 100% rename from extensions/physics_nodes/CCPhysicsSprite.h rename to extensions/physics-nodes/CCPhysicsSprite.h From 1f38636e84bde6407d9b6e2deeacac1ec6ebe2ea Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 14:02:13 +0800 Subject: [PATCH 108/116] issue #2905: step1 Box2D -> box2d --- cocos/physics/Box2D/CCPhysicsBodyInfo.cpp | 39 - cocos/physics/Box2D/CCPhysicsBodyInfo.h | 43 - cocos/physics/Box2D/CCPhysicsContactInfo.cpp | 39 - cocos/physics/Box2D/CCPhysicsContactInfo.h | 43 - cocos/physics/Box2D/CCPhysicsHelper.h | 43 - cocos/physics/Box2D/CCPhysicsJointInfo.cpp | 39 - cocos/physics/Box2D/CCPhysicsJointInfo.h | 43 - cocos/physics/Box2D/CCPhysicsShapeInfo.cpp | 39 - cocos/physics/Box2D/CCPhysicsShapeInfo.h | 43 - cocos/physics/Box2D/CCPhysicsWorldInfo.cpp | 39 - cocos/physics/Box2D/CCPhysicsWorldInfo.h | 43 - external/Box2D/Android.mk | 60 - external/Box2D/Box2D.h | 67 - .../Box2D/Collision/Shapes/b2ChainShape.cpp | 171 --- .../Box2D/Collision/Shapes/b2ChainShape.h | 102 -- .../Box2D/Collision/Shapes/b2CircleShape.cpp | 100 -- .../Box2D/Collision/Shapes/b2CircleShape.h | 91 -- .../Box2D/Collision/Shapes/b2EdgeShape.cpp | 139 -- external/Box2D/Collision/Shapes/b2EdgeShape.h | 74 - .../Box2D/Collision/Shapes/b2PolygonShape.cpp | 361 ----- .../Box2D/Collision/Shapes/b2PolygonShape.h | 95 -- external/Box2D/Collision/Shapes/b2Shape.h | 101 -- external/Box2D/Collision/b2BroadPhase.cpp | 122 -- external/Box2D/Collision/b2BroadPhase.h | 248 ---- external/Box2D/Collision/b2CollideCircle.cpp | 154 -- external/Box2D/Collision/b2CollideEdge.cpp | 698 --------- external/Box2D/Collision/b2CollidePolygon.cpp | 317 ---- external/Box2D/Collision/b2Collision.cpp | 249 ---- external/Box2D/Collision/b2Collision.h | 276 ---- external/Box2D/Collision/b2Distance.cpp | 603 -------- external/Box2D/Collision/b2Distance.h | 141 -- external/Box2D/Collision/b2DynamicTree.cpp | 775 ---------- external/Box2D/Collision/b2DynamicTree.h | 284 ---- external/Box2D/Collision/b2TimeOfImpact.cpp | 488 ------ external/Box2D/Collision/b2TimeOfImpact.h | 58 - external/Box2D/Common/b2BlockAllocator.cpp | 218 --- external/Box2D/Common/b2BlockAllocator.h | 62 - external/Box2D/Common/b2Draw.cpp | 44 - external/Box2D/Common/b2Draw.h | 81 - external/Box2D/Common/b2GrowableStack.h | 85 -- external/Box2D/Common/b2Math.cpp | 94 -- external/Box2D/Common/b2Math.h | 738 --------- external/Box2D/Common/b2Settings.cpp | 61 - external/Box2D/Common/b2Settings.h | 150 -- external/Box2D/Common/b2StackAllocator.cpp | 83 -- external/Box2D/Common/b2StackAllocator.h | 60 - external/Box2D/Common/b2Timer.cpp | 100 -- external/Box2D/Common/b2Timer.h | 45 - .../Contacts/b2ChainAndCircleContact.cpp | 54 - .../Contacts/b2ChainAndCircleContact.h | 39 - .../Contacts/b2ChainAndPolygonContact.cpp | 54 - .../Contacts/b2ChainAndPolygonContact.h | 39 - .../Dynamics/Contacts/b2CircleContact.cpp | 53 - .../Box2D/Dynamics/Contacts/b2CircleContact.h | 39 - .../Box2D/Dynamics/Contacts/b2Contact.cpp | 240 --- external/Box2D/Dynamics/Contacts/b2Contact.h | 331 ----- .../Dynamics/Contacts/b2ContactSolver.cpp | 832 ----------- .../Box2D/Dynamics/Contacts/b2ContactSolver.h | 94 -- .../Contacts/b2EdgeAndCircleContact.cpp | 50 - .../Contacts/b2EdgeAndCircleContact.h | 39 - .../Contacts/b2EdgeAndPolygonContact.cpp | 50 - .../Contacts/b2EdgeAndPolygonContact.h | 39 - .../Contacts/b2PolygonAndCircleContact.cpp | 50 - .../Contacts/b2PolygonAndCircleContact.h | 38 - .../Dynamics/Contacts/b2PolygonContact.cpp | 53 - .../Dynamics/Contacts/b2PolygonContact.h | 39 - .../Box2D/Dynamics/Joints/b2DistanceJoint.cpp | 260 ---- .../Box2D/Dynamics/Joints/b2DistanceJoint.h | 169 --- .../Box2D/Dynamics/Joints/b2FrictionJoint.cpp | 251 ---- .../Box2D/Dynamics/Joints/b2FrictionJoint.h | 119 -- .../Box2D/Dynamics/Joints/b2GearJoint.cpp | 423 ------ external/Box2D/Dynamics/Joints/b2GearJoint.h | 125 -- external/Box2D/Dynamics/Joints/b2Joint.cpp | 199 --- external/Box2D/Dynamics/Joints/b2Joint.h | 222 --- .../Box2D/Dynamics/Joints/b2MouseJoint.cpp | 217 --- external/Box2D/Dynamics/Joints/b2MouseJoint.h | 126 -- .../Dynamics/Joints/b2PrismaticJoint.cpp | 637 -------- .../Box2D/Dynamics/Joints/b2PrismaticJoint.h | 196 --- .../Box2D/Dynamics/Joints/b2PulleyJoint.cpp | 332 ----- .../Box2D/Dynamics/Joints/b2PulleyJoint.h | 143 -- .../Box2D/Dynamics/Joints/b2RevoluteJoint.cpp | 504 ------- .../Box2D/Dynamics/Joints/b2RevoluteJoint.h | 204 --- .../Box2D/Dynamics/Joints/b2RopeJoint.cpp | 241 --- external/Box2D/Dynamics/Joints/b2RopeJoint.h | 114 -- .../Box2D/Dynamics/Joints/b2WeldJoint.cpp | 330 ----- external/Box2D/Dynamics/Joints/b2WeldJoint.h | 126 -- .../Box2D/Dynamics/Joints/b2WheelJoint.cpp | 419 ------ external/Box2D/Dynamics/Joints/b2WheelJoint.h | 213 --- external/Box2D/Dynamics/b2Body.cpp | 514 ------- external/Box2D/Dynamics/b2Body.h | 846 ----------- external/Box2D/Dynamics/b2ContactManager.cpp | 293 ---- external/Box2D/Dynamics/b2ContactManager.h | 52 - external/Box2D/Dynamics/b2Fixture.cpp | 303 ---- external/Box2D/Dynamics/b2Fixture.h | 345 ----- external/Box2D/Dynamics/b2Island.cpp | 539 ------- external/Box2D/Dynamics/b2Island.h | 93 -- external/Box2D/Dynamics/b2TimeStep.h | 70 - external/Box2D/Dynamics/b2World.cpp | 1316 ----------------- external/Box2D/Dynamics/b2World.h | 349 ----- external/Box2D/Dynamics/b2WorldCallbacks.cpp | 36 - external/Box2D/Dynamics/b2WorldCallbacks.h | 155 -- external/Box2D/Rope/b2Rope.cpp | 259 ---- external/Box2D/Rope/b2Rope.h | 115 -- external/Box2D/proj.linux/.cproject | 267 ---- external/Box2D/proj.linux/.project | 110 -- external/Box2D/proj.linux/Makefile | 72 - external/Box2D/proj.linux/box2d.prf | 19 - external/Box2D/proj.win32/Box2D.vcxproj | 194 --- .../Box2D/proj.win32/Box2D.vcxproj.filters | 301 ---- external/Box2D/proj.win32/Box2D.vcxproj.user | 3 - 110 files changed, 22002 deletions(-) delete mode 100644 cocos/physics/Box2D/CCPhysicsBodyInfo.cpp delete mode 100644 cocos/physics/Box2D/CCPhysicsBodyInfo.h delete mode 100644 cocos/physics/Box2D/CCPhysicsContactInfo.cpp delete mode 100644 cocos/physics/Box2D/CCPhysicsContactInfo.h delete mode 100644 cocos/physics/Box2D/CCPhysicsHelper.h delete mode 100644 cocos/physics/Box2D/CCPhysicsJointInfo.cpp delete mode 100644 cocos/physics/Box2D/CCPhysicsJointInfo.h delete mode 100644 cocos/physics/Box2D/CCPhysicsShapeInfo.cpp delete mode 100644 cocos/physics/Box2D/CCPhysicsShapeInfo.h delete mode 100644 cocos/physics/Box2D/CCPhysicsWorldInfo.cpp delete mode 100644 cocos/physics/Box2D/CCPhysicsWorldInfo.h delete mode 100644 external/Box2D/Android.mk delete mode 100644 external/Box2D/Box2D.h delete mode 100644 external/Box2D/Collision/Shapes/b2ChainShape.cpp delete mode 100644 external/Box2D/Collision/Shapes/b2ChainShape.h delete mode 100644 external/Box2D/Collision/Shapes/b2CircleShape.cpp delete mode 100644 external/Box2D/Collision/Shapes/b2CircleShape.h delete mode 100644 external/Box2D/Collision/Shapes/b2EdgeShape.cpp delete mode 100644 external/Box2D/Collision/Shapes/b2EdgeShape.h delete mode 100644 external/Box2D/Collision/Shapes/b2PolygonShape.cpp delete mode 100644 external/Box2D/Collision/Shapes/b2PolygonShape.h delete mode 100644 external/Box2D/Collision/Shapes/b2Shape.h delete mode 100644 external/Box2D/Collision/b2BroadPhase.cpp delete mode 100644 external/Box2D/Collision/b2BroadPhase.h delete mode 100644 external/Box2D/Collision/b2CollideCircle.cpp delete mode 100644 external/Box2D/Collision/b2CollideEdge.cpp delete mode 100644 external/Box2D/Collision/b2CollidePolygon.cpp delete mode 100644 external/Box2D/Collision/b2Collision.cpp delete mode 100644 external/Box2D/Collision/b2Collision.h delete mode 100644 external/Box2D/Collision/b2Distance.cpp delete mode 100644 external/Box2D/Collision/b2Distance.h delete mode 100644 external/Box2D/Collision/b2DynamicTree.cpp delete mode 100644 external/Box2D/Collision/b2DynamicTree.h delete mode 100644 external/Box2D/Collision/b2TimeOfImpact.cpp delete mode 100644 external/Box2D/Collision/b2TimeOfImpact.h delete mode 100644 external/Box2D/Common/b2BlockAllocator.cpp delete mode 100644 external/Box2D/Common/b2BlockAllocator.h delete mode 100644 external/Box2D/Common/b2Draw.cpp delete mode 100644 external/Box2D/Common/b2Draw.h delete mode 100644 external/Box2D/Common/b2GrowableStack.h delete mode 100644 external/Box2D/Common/b2Math.cpp delete mode 100644 external/Box2D/Common/b2Math.h delete mode 100644 external/Box2D/Common/b2Settings.cpp delete mode 100644 external/Box2D/Common/b2Settings.h delete mode 100644 external/Box2D/Common/b2StackAllocator.cpp delete mode 100644 external/Box2D/Common/b2StackAllocator.h delete mode 100644 external/Box2D/Common/b2Timer.cpp delete mode 100644 external/Box2D/Common/b2Timer.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2CircleContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2CircleContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2Contact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2Contact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2ContactSolver.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h delete mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp delete mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonContact.h delete mode 100644 external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2DistanceJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2FrictionJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2GearJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2GearJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2Joint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2Joint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2MouseJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2MouseJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2PrismaticJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2PulleyJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2RevoluteJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2RopeJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2RopeJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2WeldJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2WeldJoint.h delete mode 100644 external/Box2D/Dynamics/Joints/b2WheelJoint.cpp delete mode 100644 external/Box2D/Dynamics/Joints/b2WheelJoint.h delete mode 100644 external/Box2D/Dynamics/b2Body.cpp delete mode 100644 external/Box2D/Dynamics/b2Body.h delete mode 100644 external/Box2D/Dynamics/b2ContactManager.cpp delete mode 100644 external/Box2D/Dynamics/b2ContactManager.h delete mode 100644 external/Box2D/Dynamics/b2Fixture.cpp delete mode 100644 external/Box2D/Dynamics/b2Fixture.h delete mode 100644 external/Box2D/Dynamics/b2Island.cpp delete mode 100644 external/Box2D/Dynamics/b2Island.h delete mode 100644 external/Box2D/Dynamics/b2TimeStep.h delete mode 100644 external/Box2D/Dynamics/b2World.cpp delete mode 100644 external/Box2D/Dynamics/b2World.h delete mode 100644 external/Box2D/Dynamics/b2WorldCallbacks.cpp delete mode 100644 external/Box2D/Dynamics/b2WorldCallbacks.h delete mode 100644 external/Box2D/Rope/b2Rope.cpp delete mode 100644 external/Box2D/Rope/b2Rope.h delete mode 100644 external/Box2D/proj.linux/.cproject delete mode 100644 external/Box2D/proj.linux/.project delete mode 100644 external/Box2D/proj.linux/Makefile delete mode 100644 external/Box2D/proj.linux/box2d.prf delete mode 100644 external/Box2D/proj.win32/Box2D.vcxproj delete mode 100644 external/Box2D/proj.win32/Box2D.vcxproj.filters delete mode 100644 external/Box2D/proj.win32/Box2D.vcxproj.user diff --git a/cocos/physics/Box2D/CCPhysicsBodyInfo.cpp b/cocos/physics/Box2D/CCPhysicsBodyInfo.cpp deleted file mode 100644 index bfa20b616a..0000000000 --- a/cocos/physics/Box2D/CCPhysicsBodyInfo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "CCPhysicsBodyInfo.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) -NS_CC_BEGIN - -PhysicsBodyInfo::PhysicsBodyInfo() -{ -} - -PhysicsBodyInfo::~PhysicsBodyInfo() -{ -} - -NS_CC_END -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsBodyInfo.h b/cocos/physics/Box2D/CCPhysicsBodyInfo.h deleted file mode 100644 index 730837ed9d..0000000000 --- a/cocos/physics/Box2D/CCPhysicsBodyInfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_BODY_INFO_H__ -#define __CCPHYSICS_BODY_INFO_H__ -#include "platform/CCPlatformMacros.h" -NS_CC_BEGIN - -class PhysicsBodyInfo -{ -public: - PhysicsBodyInfo(); - ~PhysicsBodyInfo(); -}; - -NS_CC_END -#endif // __CCPHYSICS_BODY_INFO_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsContactInfo.cpp b/cocos/physics/Box2D/CCPhysicsContactInfo.cpp deleted file mode 100644 index 41eaa4f831..0000000000 --- a/cocos/physics/Box2D/CCPhysicsContactInfo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "CCPhysicsContactInfo.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) -NS_CC_BEGIN - -PhysicsContactInfo::PhysicsContactInfo() -{ -} - -PhysicsContactInfo::~PhysicsContactInfo() -{ -} - -NS_CC_END -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsContactInfo.h b/cocos/physics/Box2D/CCPhysicsContactInfo.h deleted file mode 100644 index b592caa0af..0000000000 --- a/cocos/physics/Box2D/CCPhysicsContactInfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_CONTACT_INFO_H__ -#define __CCPHYSICS_CONTACT_INFO_H__ -#include "platform/CCPlatformMacros.h" -NS_CC_BEGIN - -class PhysicsContactInfo -{ -public: - PhysicsContactInfo(); - ~PhysicsContactInfo(); -}; - -NS_CC_END -#endif // __CCPHYSICS_CONTACT_INFO_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsHelper.h b/cocos/physics/Box2D/CCPhysicsHelper.h deleted file mode 100644 index 86ef7d74ee..0000000000 --- a/cocos/physics/Box2D/CCPhysicsHelper.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_HELPER_H__ -#define __CCPHYSICS_HELPER_H__ - -#include "platform/CCPlatformMacros.h" -#include "cocoa/CCGeometry.h" - -NS_CC_BEGIN - -class PhysicsHelper -{ -}; - -NS_CC_END -#endif // __CCPHYSICS_HELPER_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsJointInfo.cpp b/cocos/physics/Box2D/CCPhysicsJointInfo.cpp deleted file mode 100644 index 753ba41534..0000000000 --- a/cocos/physics/Box2D/CCPhysicsJointInfo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "CCPhysicsJointInfo.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) -NS_CC_BEGIN - -PhysicsJointInfo::PhysicsJointInfo() -{ -} - -PhysicsJointInfo::~PhysicsJointInfo() -{ -} - -NS_CC_END -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsJointInfo.h b/cocos/physics/Box2D/CCPhysicsJointInfo.h deleted file mode 100644 index abcf089387..0000000000 --- a/cocos/physics/Box2D/CCPhysicsJointInfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_JOINT_INFO_H__ -#define __CCPHYSICS_JOINT_INFO_H__ -#include "platform/CCPlatformMacros.h" -NS_CC_BEGIN - -class PhysicsJointInfo -{ -public: - PhysicsJointInfo(); - ~PhysicsJointInfo(); -}; - -NS_CC_END -#endif // __CCPHYSICS_JOINT_INFO_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsShapeInfo.cpp b/cocos/physics/Box2D/CCPhysicsShapeInfo.cpp deleted file mode 100644 index a89ba7dae7..0000000000 --- a/cocos/physics/Box2D/CCPhysicsShapeInfo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "CCPhysicsShapeInfo.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) -NS_CC_BEGIN - -PhysicsShapeInfo::PhysicsShapeInfo() -{ -} - -PhysicsShapeInfo::~PhysicsShapeInfo() -{ -} - -NS_CC_END -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsShapeInfo.h b/cocos/physics/Box2D/CCPhysicsShapeInfo.h deleted file mode 100644 index 9091001887..0000000000 --- a/cocos/physics/Box2D/CCPhysicsShapeInfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_SHAPE_INFO_H__ -#define __CCPHYSICS_SHAPE_INFO_H__ -#include "platform/CCPlatformMacros.h" -NS_CC_BEGIN - -class PhysicsShapeInfo -{ -public: - PhysicsShapeInfo(); - ~PhysicsShapeInfo(); -}; - -NS_CC_END -#endif // __CCPHYSICS_SHAPE_INFO_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsWorldInfo.cpp b/cocos/physics/Box2D/CCPhysicsWorldInfo.cpp deleted file mode 100644 index 0de6c00d82..0000000000 --- a/cocos/physics/Box2D/CCPhysicsWorldInfo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "CCPhysicsWorldInfo.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) -NS_CC_BEGIN - -PhysicsWorldInfo::PhysicsWorldInfo() -{ -} - -PhysicsWorldInfo::~PhysicsWorldInfo() -{ -} - -NS_CC_END -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/Box2D/CCPhysicsWorldInfo.h b/cocos/physics/Box2D/CCPhysicsWorldInfo.h deleted file mode 100644 index bcc09124db..0000000000 --- a/cocos/physics/Box2D/CCPhysicsWorldInfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "../CCPhysicsSetting.h" -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) - -#ifndef __CCPHYSICS_WORLD_INFO_H__ -#define __CCPHYSICS_WORLD_INFO_H__ -#include "platform/CCPlatformMacros.h" -NS_CC_BEGIN - -class PhysicsWorldInfo -{ -public: - PhysicsWorldInfo(); - ~PhysicsWorldInfo(); -}; - -NS_CC_END -#endif // __CCPHYSICS_WORLD_INFO_H__ - -#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/external/Box2D/Android.mk b/external/Box2D/Android.mk deleted file mode 100644 index c366750c01..0000000000 --- a/external/Box2D/Android.mk +++ /dev/null @@ -1,60 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := box2d_static - -LOCAL_MODULE_FILENAME := libbox2d - -LOCAL_SRC_FILES := \ -Collision/b2BroadPhase.cpp \ -Collision/b2CollideCircle.cpp \ -Collision/b2CollideEdge.cpp \ -Collision/b2CollidePolygon.cpp \ -Collision/b2Collision.cpp \ -Collision/b2Distance.cpp \ -Collision/b2DynamicTree.cpp \ -Collision/b2TimeOfImpact.cpp \ -Collision/Shapes/b2ChainShape.cpp \ -Collision/Shapes/b2CircleShape.cpp \ -Collision/Shapes/b2EdgeShape.cpp \ -Collision/Shapes/b2PolygonShape.cpp \ -Common/b2BlockAllocator.cpp \ -Common/b2Draw.cpp \ -Common/b2Math.cpp \ -Common/b2Settings.cpp \ -Common/b2StackAllocator.cpp \ -Common/b2Timer.cpp \ -Dynamics/b2Body.cpp \ -Dynamics/b2ContactManager.cpp \ -Dynamics/b2Fixture.cpp \ -Dynamics/b2Island.cpp \ -Dynamics/b2World.cpp \ -Dynamics/b2WorldCallbacks.cpp \ -Dynamics/Contacts/b2ChainAndCircleContact.cpp \ -Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ -Dynamics/Contacts/b2CircleContact.cpp \ -Dynamics/Contacts/b2Contact.cpp \ -Dynamics/Contacts/b2ContactSolver.cpp \ -Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ -Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ -Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ -Dynamics/Contacts/b2PolygonContact.cpp \ -Dynamics/Joints/b2DistanceJoint.cpp \ -Dynamics/Joints/b2FrictionJoint.cpp \ -Dynamics/Joints/b2GearJoint.cpp \ -Dynamics/Joints/b2Joint.cpp \ -Dynamics/Joints/b2MouseJoint.cpp \ -Dynamics/Joints/b2PrismaticJoint.cpp \ -Dynamics/Joints/b2PulleyJoint.cpp \ -Dynamics/Joints/b2RevoluteJoint.cpp \ -Dynamics/Joints/b2RopeJoint.cpp \ -Dynamics/Joints/b2WeldJoint.cpp \ -Dynamics/Joints/b2WheelJoint.cpp \ -Rope/b2Rope.cpp - -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. - -include $(BUILD_STATIC_LIBRARY) diff --git a/external/Box2D/Box2D.h b/external/Box2D/Box2D.h deleted file mode 100644 index f674d82269..0000000000 --- a/external/Box2D/Box2D.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef BOX2D_H -#define BOX2D_H - -/** -\mainpage Box2D API Documentation - -\section intro_sec Getting Started - -For documentation please see http://box2d.org/documentation.html - -For discussion please visit http://box2d.org/forum -*/ - -// These include files constitute the main Box2D API - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/external/Box2D/Collision/Shapes/b2ChainShape.cpp b/external/Box2D/Collision/Shapes/b2ChainShape.cpp deleted file mode 100644 index 79b4304b5b..0000000000 --- a/external/Box2D/Collision/Shapes/b2ChainShape.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -using namespace std; - -b2ChainShape::~b2ChainShape() -{ - b2Free(m_vertices); - m_vertices = NULL; - m_count = 0; -} - -void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) -{ - b2Assert(m_vertices == NULL && m_count == 0); - b2Assert(count >= 3); - m_count = count + 1; - m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); - m_vertices[count] = m_vertices[0]; - m_prevVertex = m_vertices[m_count - 2]; - m_nextVertex = m_vertices[1]; - m_hasPrevVertex = true; - m_hasNextVertex = true; -} - -void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) -{ - b2Assert(m_vertices == NULL && m_count == 0); - b2Assert(count >= 2); - m_count = count; - m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); - memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); - m_hasPrevVertex = false; - m_hasNextVertex = false; -} - -void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) -{ - m_prevVertex = prevVertex; - m_hasPrevVertex = true; -} - -void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) -{ - m_nextVertex = nextVertex; - m_hasNextVertex = true; -} - -b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2ChainShape)); - b2ChainShape* clone = new (mem) b2ChainShape; - clone->CreateChain(m_vertices, m_count); - clone->m_prevVertex = m_prevVertex; - clone->m_nextVertex = m_nextVertex; - clone->m_hasPrevVertex = m_hasPrevVertex; - clone->m_hasNextVertex = m_hasNextVertex; - return clone; -} - -int32 b2ChainShape::GetChildCount() const -{ - // edge count = vertex count - 1 - return m_count - 1; -} - -void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const -{ - b2Assert(0 <= index && index < m_count - 1); - edge->m_type = b2Shape::e_edge; - edge->m_radius = m_radius; - - edge->m_vertex1 = m_vertices[index + 0]; - edge->m_vertex2 = m_vertices[index + 1]; - - if (index > 0) - { - edge->m_vertex0 = m_vertices[index - 1]; - edge->m_hasVertex0 = true; - } - else - { - edge->m_vertex0 = m_prevVertex; - edge->m_hasVertex0 = m_hasPrevVertex; - } - - if (index < m_count - 2) - { - edge->m_vertex3 = m_vertices[index + 2]; - edge->m_hasVertex3 = true; - } - else - { - edge->m_vertex3 = m_nextVertex; - edge->m_hasVertex3 = m_hasNextVertex; - } -} - -bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - B2_NOT_USED(xf); - B2_NOT_USED(p); - return false; -} - -bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - b2Assert(childIndex < m_count); - - b2EdgeShape edgeShape; - - int32 i1 = childIndex; - int32 i2 = childIndex + 1; - if (i2 == m_count) - { - i2 = 0; - } - - edgeShape.m_vertex1 = m_vertices[i1]; - edgeShape.m_vertex2 = m_vertices[i2]; - - return edgeShape.RayCast(output, input, xf, 0); -} - -void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - b2Assert(childIndex < m_count); - - int32 i1 = childIndex; - int32 i2 = childIndex + 1; - if (i2 == m_count) - { - i2 = 0; - } - - b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); - b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); - - aabb->lowerBound = b2Min(v1, v2); - aabb->upperBound = b2Max(v1, v2); -} - -void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const -{ - B2_NOT_USED(density); - - massData->mass = 0.0f; - massData->center.SetZero(); - massData->I = 0.0f; -} diff --git a/external/Box2D/Collision/Shapes/b2ChainShape.h b/external/Box2D/Collision/Shapes/b2ChainShape.h deleted file mode 100644 index 9c9a9eaa7d..0000000000 --- a/external/Box2D/Collision/Shapes/b2ChainShape.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -* Copyright (c) 2006-2010 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. -*/ - -#ifndef B2_CHAIN_SHAPE_H -#define B2_CHAIN_SHAPE_H - -#include - -class b2EdgeShape; - -/// A chain shape is a free form sequence of line segments. -/// The chain has two-sided collision, so you can use inside and outside collision. -/// Therefore, you may use any winding order. -/// Since there may be many vertices, they are allocated using b2Alloc. -/// Connectivity information is used to create smooth collisions. -/// WARNING: The chain will not collide properly if there are self-intersections. -class b2ChainShape : public b2Shape -{ -public: - b2ChainShape(); - - /// The destructor frees the vertices using b2Free. - ~b2ChainShape(); - - /// Create a loop. This automatically adjusts connectivity. - /// @param vertices an array of vertices, these are copied - /// @param count the vertex count - void CreateLoop(const b2Vec2* vertices, int32 count); - - /// Create a chain with isolated end vertices. - /// @param vertices an array of vertices, these are copied - /// @param count the vertex count - void CreateChain(const b2Vec2* vertices, int32 count); - - /// Establish connectivity to a vertex that precedes the first vertex. - /// Don't call this for loops. - void SetPrevVertex(const b2Vec2& prevVertex); - - /// Establish connectivity to a vertex that follows the last vertex. - /// Don't call this for loops. - void SetNextVertex(const b2Vec2& nextVertex); - - /// Implement b2Shape. Vertices are cloned using b2Alloc. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Get a child edge. - void GetChildEdge(b2EdgeShape* edge, int32 index) const; - - /// This always return false. - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// Chains have zero mass. - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// The vertices. Owned by this class. - b2Vec2* m_vertices; - - /// The vertex count. - int32 m_count; - - b2Vec2 m_prevVertex, m_nextVertex; - bool m_hasPrevVertex, m_hasNextVertex; -}; - -inline b2ChainShape::b2ChainShape() -{ - m_type = e_chain; - m_radius = b2_polygonRadius; - m_vertices = NULL; - m_count = 0; - m_hasPrevVertex = false; - m_hasNextVertex = false; -} - -#endif diff --git a/external/Box2D/Collision/Shapes/b2CircleShape.cpp b/external/Box2D/Collision/Shapes/b2CircleShape.cpp deleted file mode 100644 index 587ca960b2..0000000000 --- a/external/Box2D/Collision/Shapes/b2CircleShape.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -using namespace std; - -b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2CircleShape)); - b2CircleShape* clone = new (mem) b2CircleShape; - *clone = *this; - return clone; -} - -int32 b2CircleShape::GetChildCount() const -{ - return 1; -} - -bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const -{ - b2Vec2 center = transform.p + b2Mul(transform.q, m_p); - b2Vec2 d = p - center; - return b2Dot(d, d) <= m_radius * m_radius; -} - -// Collision Detection in Interactive 3D Environments by Gino van den Bergen -// From Section 3.1.2 -// x = s + a * r -// norm(x) = radius -bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 position = transform.p + b2Mul(transform.q, m_p); - b2Vec2 s = input.p1 - position; - float32 b = b2Dot(s, s) - m_radius * m_radius; - - // Solve quadratic equation. - b2Vec2 r = input.p2 - input.p1; - float32 c = b2Dot(s, r); - float32 rr = b2Dot(r, r); - float32 sigma = c * c - rr * b; - - // Check for negative discriminant and short segment. - if (sigma < 0.0f || rr < b2_epsilon) - { - return false; - } - - // Find the point of intersection of the line with the circle. - float32 a = -(c + b2Sqrt(sigma)); - - // Is the intersection point on the segment? - if (0.0f <= a && a <= input.maxFraction * rr) - { - a /= rr; - output->fraction = a; - output->normal = s + a * r; - output->normal.Normalize(); - return true; - } - - return false; -} - -void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 p = transform.p + b2Mul(transform.q, m_p); - aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); - aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); -} - -void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const -{ - massData->mass = density * b2_pi * m_radius * m_radius; - massData->center = m_p; - - // inertia about the local origin - massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); -} diff --git a/external/Box2D/Collision/Shapes/b2CircleShape.h b/external/Box2D/Collision/Shapes/b2CircleShape.h deleted file mode 100644 index c4e23a475b..0000000000 --- a/external/Box2D/Collision/Shapes/b2CircleShape.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CIRCLE_SHAPE_H -#define B2_CIRCLE_SHAPE_H - -#include - -/// A circle shape. -class b2CircleShape : public b2Shape -{ -public: - b2CircleShape(); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Implement b2Shape. - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// Get the supporting vertex index in the given direction. - int32 GetSupport(const b2Vec2& d) const; - - /// Get the supporting vertex in the given direction. - const b2Vec2& GetSupportVertex(const b2Vec2& d) const; - - /// Get the vertex count. - int32 GetVertexCount() const { return 1; } - - /// Get a vertex by index. Used by b2Distance. - const b2Vec2& GetVertex(int32 index) const; - - /// Position - b2Vec2 m_p; -}; - -inline b2CircleShape::b2CircleShape() -{ - m_type = e_circle; - m_radius = 0.0f; - m_p.SetZero(); -} - -inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const -{ - B2_NOT_USED(d); - return 0; -} - -inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const -{ - B2_NOT_USED(d); - return m_p; -} - -inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const -{ - B2_NOT_USED(index); - b2Assert(index == 0); - return m_p; -} - -#endif diff --git a/external/Box2D/Collision/Shapes/b2EdgeShape.cpp b/external/Box2D/Collision/Shapes/b2EdgeShape.cpp deleted file mode 100644 index 7b09e55bf4..0000000000 --- a/external/Box2D/Collision/Shapes/b2EdgeShape.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -using namespace std; - -void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) -{ - m_vertex1 = v1; - m_vertex2 = v2; - m_hasVertex0 = false; - m_hasVertex3 = false; -} - -b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2EdgeShape)); - b2EdgeShape* clone = new (mem) b2EdgeShape; - *clone = *this; - return clone; -} - -int32 b2EdgeShape::GetChildCount() const -{ - return 1; -} - -bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - B2_NOT_USED(xf); - B2_NOT_USED(p); - return false; -} - -// p = p1 + t * d -// v = v1 + s * e -// p1 + t * d = v1 + s * e -// s * e - t * d = p1 - v1 -bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - // Put the ray into the edge's frame of reference. - b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); - b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); - b2Vec2 d = p2 - p1; - - b2Vec2 v1 = m_vertex1; - b2Vec2 v2 = m_vertex2; - b2Vec2 e = v2 - v1; - b2Vec2 normal(e.y, -e.x); - normal.Normalize(); - - // q = p1 + t * d - // dot(normal, q - v1) = 0 - // dot(normal, p1 - v1) + t * dot(normal, d) = 0 - float32 numerator = b2Dot(normal, v1 - p1); - float32 denominator = b2Dot(normal, d); - - if (denominator == 0.0f) - { - return false; - } - - float32 t = numerator / denominator; - if (t < 0.0f || input.maxFraction < t) - { - return false; - } - - b2Vec2 q = p1 + t * d; - - // q = v1 + s * r - // s = dot(q - v1, r) / dot(r, r) - b2Vec2 r = v2 - v1; - float32 rr = b2Dot(r, r); - if (rr == 0.0f) - { - return false; - } - - float32 s = b2Dot(q - v1, r) / rr; - if (s < 0.0f || 1.0f < s) - { - return false; - } - - output->fraction = t; - if (numerator > 0.0f) - { - output->normal = -normal; - } - else - { - output->normal = normal; - } - return true; -} - -void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 v1 = b2Mul(xf, m_vertex1); - b2Vec2 v2 = b2Mul(xf, m_vertex2); - - b2Vec2 lower = b2Min(v1, v2); - b2Vec2 upper = b2Max(v1, v2); - - b2Vec2 r(m_radius, m_radius); - aabb->lowerBound = lower - r; - aabb->upperBound = upper + r; -} - -void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const -{ - B2_NOT_USED(density); - - massData->mass = 0.0f; - massData->center = 0.5f * (m_vertex1 + m_vertex2); - massData->I = 0.0f; -} diff --git a/external/Box2D/Collision/Shapes/b2EdgeShape.h b/external/Box2D/Collision/Shapes/b2EdgeShape.h deleted file mode 100644 index 6163bcbf1c..0000000000 --- a/external/Box2D/Collision/Shapes/b2EdgeShape.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (c) 2006-2010 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. -*/ - -#ifndef B2_EDGE_SHAPE_H -#define B2_EDGE_SHAPE_H - -#include - -/// A line segment (edge) shape. These can be connected in chains or loops -/// to other edge shapes. The connectivity information is used to ensure -/// correct contact normals. -class b2EdgeShape : public b2Shape -{ -public: - b2EdgeShape(); - - /// Set this as an isolated edge. - void Set(const b2Vec2& v1, const b2Vec2& v2); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// These are the edge vertices - b2Vec2 m_vertex1, m_vertex2; - - /// Optional adjacent vertices. These are used for smooth collision. - b2Vec2 m_vertex0, m_vertex3; - bool m_hasVertex0, m_hasVertex3; -}; - -inline b2EdgeShape::b2EdgeShape() -{ - m_type = e_edge; - m_radius = b2_polygonRadius; - m_vertex0.x = 0.0f; - m_vertex0.y = 0.0f; - m_vertex3.x = 0.0f; - m_vertex3.y = 0.0f; - m_hasVertex0 = false; - m_hasVertex3 = false; -} - -#endif diff --git a/external/Box2D/Collision/Shapes/b2PolygonShape.cpp b/external/Box2D/Collision/Shapes/b2PolygonShape.cpp deleted file mode 100644 index c04c1dc49b..0000000000 --- a/external/Box2D/Collision/Shapes/b2PolygonShape.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2PolygonShape)); - b2PolygonShape* clone = new (mem) b2PolygonShape; - *clone = *this; - return clone; -} - -void b2PolygonShape::SetAsBox(float32 hx, float32 hy) -{ - m_vertexCount = 4; - m_vertices[0].Set(-hx, -hy); - m_vertices[1].Set( hx, -hy); - m_vertices[2].Set( hx, hy); - m_vertices[3].Set(-hx, hy); - m_normals[0].Set(0.0f, -1.0f); - m_normals[1].Set(1.0f, 0.0f); - m_normals[2].Set(0.0f, 1.0f); - m_normals[3].Set(-1.0f, 0.0f); - m_centroid.SetZero(); -} - -void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) -{ - m_vertexCount = 4; - m_vertices[0].Set(-hx, -hy); - m_vertices[1].Set( hx, -hy); - m_vertices[2].Set( hx, hy); - m_vertices[3].Set(-hx, hy); - m_normals[0].Set(0.0f, -1.0f); - m_normals[1].Set(1.0f, 0.0f); - m_normals[2].Set(0.0f, 1.0f); - m_normals[3].Set(-1.0f, 0.0f); - m_centroid = center; - - b2Transform xf; - xf.p = center; - xf.q.Set(angle); - - // Transform vertices and normals. - for (int32 i = 0; i < m_vertexCount; ++i) - { - m_vertices[i] = b2Mul(xf, m_vertices[i]); - m_normals[i] = b2Mul(xf.q, m_normals[i]); - } -} - -int32 b2PolygonShape::GetChildCount() const -{ - return 1; -} - -static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) -{ - b2Assert(count >= 3); - - b2Vec2 c; c.Set(0.0f, 0.0f); - float32 area = 0.0f; - - // pRef is the reference point for forming triangles. - // It's location doesn't change the result (except for rounding error). - b2Vec2 pRef(0.0f, 0.0f); -#if 0 - // This code would put the reference point inside the polygon. - for (int32 i = 0; i < count; ++i) - { - pRef += vs[i]; - } - pRef *= 1.0f / count; -#endif - - const float32 inv3 = 1.0f / 3.0f; - - for (int32 i = 0; i < count; ++i) - { - // Triangle vertices. - b2Vec2 p1 = pRef; - b2Vec2 p2 = vs[i]; - b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; - - b2Vec2 e1 = p2 - p1; - b2Vec2 e2 = p3 - p1; - - float32 D = b2Cross(e1, e2); - - float32 triangleArea = 0.5f * D; - area += triangleArea; - - // Area weighted centroid - c += triangleArea * inv3 * (p1 + p2 + p3); - } - - // Centroid - b2Assert(area > b2_epsilon); - c *= 1.0f / area; - return c; -} - -void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) -{ - b2Assert(3 <= count && count <= b2_maxPolygonVertices); - m_vertexCount = count; - - // Copy vertices. - for (int32 i = 0; i < m_vertexCount; ++i) - { - m_vertices[i] = vertices[i]; - } - - // Compute normals. Ensure the edges have non-zero length. - for (int32 i = 0; i < m_vertexCount; ++i) - { - int32 i1 = i; - int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; - b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; - b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); - m_normals[i] = b2Cross(edge, 1.0f); - m_normals[i].Normalize(); - } - -#ifdef _DEBUG - // Ensure the polygon is convex and the interior - // is to the left of each edge. - for (int32 i = 0; i < m_vertexCount; ++i) - { - int32 i1 = i; - int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; - b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; - - for (int32 j = 0; j < m_vertexCount; ++j) - { - // Don't check vertices on the current edge. - if (j == i1 || j == i2) - { - continue; - } - - b2Vec2 r = m_vertices[j] - m_vertices[i1]; - - // If this crashes, your polygon is non-convex, has colinear edges, - // or the winding order is wrong. - float32 s = b2Cross(edge, r); - b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order"); - } - } -#endif - - // Compute the polygon centroid. - m_centroid = ComputeCentroid(m_vertices, m_vertexCount); -} - -bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); - - for (int32 i = 0; i < m_vertexCount; ++i) - { - float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); - if (dot > 0.0f) - { - return false; - } - } - - return true; -} - -bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - // Put the ray into the polygon's frame of reference. - b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); - b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); - b2Vec2 d = p2 - p1; - - float32 lower = 0.0f, upper = input.maxFraction; - - int32 index = -1; - - for (int32 i = 0; i < m_vertexCount; ++i) - { - // p = p1 + a * d - // dot(normal, p - v) = 0 - // dot(normal, p1 - v) + a * dot(normal, d) = 0 - float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); - float32 denominator = b2Dot(m_normals[i], d); - - if (denominator == 0.0f) - { - if (numerator < 0.0f) - { - return false; - } - } - else - { - // Note: we want this predicate without division: - // lower < numerator / denominator, where denominator < 0 - // Since denominator < 0, we have to flip the inequality: - // lower < numerator / denominator <==> denominator * lower > numerator. - if (denominator < 0.0f && numerator < lower * denominator) - { - // Increase lower. - // The segment enters this half-space. - lower = numerator / denominator; - index = i; - } - else if (denominator > 0.0f && numerator < upper * denominator) - { - // Decrease upper. - // The segment exits this half-space. - upper = numerator / denominator; - } - } - - // The use of epsilon here causes the assert on lower to trip - // in some cases. Apparently the use of epsilon was to make edge - // shapes work, but now those are handled separately. - //if (upper < lower - b2_epsilon) - if (upper < lower) - { - return false; - } - } - - b2Assert(0.0f <= lower && lower <= input.maxFraction); - - if (index >= 0) - { - output->fraction = lower; - output->normal = b2Mul(xf.q, m_normals[index]); - return true; - } - - return false; -} - -void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 lower = b2Mul(xf, m_vertices[0]); - b2Vec2 upper = lower; - - for (int32 i = 1; i < m_vertexCount; ++i) - { - b2Vec2 v = b2Mul(xf, m_vertices[i]); - lower = b2Min(lower, v); - upper = b2Max(upper, v); - } - - b2Vec2 r(m_radius, m_radius); - aabb->lowerBound = lower - r; - aabb->upperBound = upper + r; -} - -void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const -{ - // Polygon mass, centroid, and inertia. - // Let rho be the polygon density in mass per unit area. - // Then: - // mass = rho * int(dA) - // centroid.x = (1/mass) * rho * int(x * dA) - // centroid.y = (1/mass) * rho * int(y * dA) - // I = rho * int((x*x + y*y) * dA) - // - // We can compute these integrals by summing all the integrals - // for each triangle of the polygon. To evaluate the integral - // for a single triangle, we make a change of variables to - // the (u,v) coordinates of the triangle: - // x = x0 + e1x * u + e2x * v - // y = y0 + e1y * u + e2y * v - // where 0 <= u && 0 <= v && u + v <= 1. - // - // We integrate u from [0,1-v] and then v from [0,1]. - // We also need to use the Jacobian of the transformation: - // D = cross(e1, e2) - // - // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) - // - // The rest of the derivation is handled by computer algebra. - - b2Assert(m_vertexCount >= 3); - - b2Vec2 center; center.Set(0.0f, 0.0f); - float32 area = 0.0f; - float32 I = 0.0f; - - // s is the reference point for forming triangles. - // It's location doesn't change the result (except for rounding error). - b2Vec2 s(0.0f, 0.0f); - - // This code would put the reference point inside the polygon. - for (int32 i = 0; i < m_vertexCount; ++i) - { - s += m_vertices[i]; - } - s *= 1.0f / m_vertexCount; - - const float32 k_inv3 = 1.0f / 3.0f; - - for (int32 i = 0; i < m_vertexCount; ++i) - { - // Triangle vertices. - b2Vec2 e1 = m_vertices[i] - s; - b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s; - - float32 D = b2Cross(e1, e2); - - float32 triangleArea = 0.5f * D; - area += triangleArea; - - // Area weighted centroid - center += triangleArea * k_inv3 * (e1 + e2); - - float32 ex1 = e1.x, ey1 = e1.y; - float32 ex2 = e2.x, ey2 = e2.y; - - float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; - float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; - - I += (0.25f * k_inv3 * D) * (intx2 + inty2); - } - - // Total mass - massData->mass = density * area; - - // Center of mass - b2Assert(area > b2_epsilon); - center *= 1.0f / area; - massData->center = center + s; - - // Inertia tensor relative to the local origin (point s). - massData->I = density * I; - - // Shift to center of mass then to original body origin. - massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); -} diff --git a/external/Box2D/Collision/Shapes/b2PolygonShape.h b/external/Box2D/Collision/Shapes/b2PolygonShape.h deleted file mode 100644 index 70daccb2ff..0000000000 --- a/external/Box2D/Collision/Shapes/b2PolygonShape.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_SHAPE_H -#define B2_POLYGON_SHAPE_H - -#include - -/// A convex polygon. It is assumed that the interior of the polygon is to -/// the left of each edge. -/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. -/// In most cases you should not need many vertices for a convex polygon. -class b2PolygonShape : public b2Shape -{ -public: - b2PolygonShape(); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Copy vertices. This assumes the vertices define a convex polygon. - /// It is assumed that the exterior is the the right of each edge. - /// The count must be in the range [3, b2_maxPolygonVertices]. - void Set(const b2Vec2* vertices, int32 vertexCount); - - /// Build vertices to represent an axis-aligned box. - /// @param hx the half-width. - /// @param hy the half-height. - void SetAsBox(float32 hx, float32 hy); - - /// Build vertices to represent an oriented box. - /// @param hx the half-width. - /// @param hy the half-height. - /// @param center the center of the box in local coordinates. - /// @param angle the rotation of the box in local coordinates. - void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); - - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// Get the vertex count. - int32 GetVertexCount() const { return m_vertexCount; } - - /// Get a vertex by index. - const b2Vec2& GetVertex(int32 index) const; - - b2Vec2 m_centroid; - b2Vec2 m_vertices[b2_maxPolygonVertices]; - b2Vec2 m_normals[b2_maxPolygonVertices]; - int32 m_vertexCount; -}; - -inline b2PolygonShape::b2PolygonShape() -{ - m_type = e_polygon; - m_radius = b2_polygonRadius; - m_vertexCount = 0; - m_centroid.SetZero(); -} - -inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const -{ - b2Assert(0 <= index && index < m_vertexCount); - return m_vertices[index]; -} - -#endif diff --git a/external/Box2D/Collision/Shapes/b2Shape.h b/external/Box2D/Collision/Shapes/b2Shape.h deleted file mode 100644 index 2e2aedd14a..0000000000 --- a/external/Box2D/Collision/Shapes/b2Shape.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_SHAPE_H -#define B2_SHAPE_H - -#include -#include -#include - -/// This holds the mass data computed for a shape. -struct b2MassData -{ - /// The mass of the shape, usually in kilograms. - float32 mass; - - /// The position of the shape's centroid relative to the shape's origin. - b2Vec2 center; - - /// The rotational inertia of the shape about the local origin. - float32 I; -}; - -/// A shape is used for collision detection. You can create a shape however you like. -/// Shapes used for simulation in b2World are created automatically when a b2Fixture -/// is created. Shapes may encapsulate a one or more child shapes. -class b2Shape -{ -public: - - enum Type - { - e_circle = 0, - e_edge = 1, - e_polygon = 2, - e_chain = 3, - e_typeCount = 4 - }; - - virtual ~b2Shape() {} - - /// Clone the concrete shape using the provided allocator. - virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; - - /// Get the type of this shape. You can use this to down cast to the concrete shape. - /// @return the shape type. - Type GetType() const; - - /// Get the number of child primitives. - virtual int32 GetChildCount() const = 0; - - /// Test a point for containment in this shape. This only works for convex shapes. - /// @param xf the shape world transform. - /// @param p a point in world coordinates. - virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; - - /// Cast a ray against a child shape. - /// @param output the ray-cast results. - /// @param input the ray-cast input parameters. - /// @param transform the transform to be applied to the shape. - /// @param childIndex the child shape index - virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const = 0; - - /// Given a transform, compute the associated axis aligned bounding box for a child shape. - /// @param aabb returns the axis aligned box. - /// @param xf the world transform of the shape. - /// @param childIndex the child shape - virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; - - /// Compute the mass properties of this shape using its dimensions and density. - /// The inertia tensor is computed about the local origin. - /// @param massData returns the mass data for this shape. - /// @param density the density in kilograms per meter squared. - virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; - - Type m_type; - float32 m_radius; -}; - -inline b2Shape::Type b2Shape::GetType() const -{ - return m_type; -} - -#endif diff --git a/external/Box2D/Collision/b2BroadPhase.cpp b/external/Box2D/Collision/b2BroadPhase.cpp deleted file mode 100644 index 431f6de1ee..0000000000 --- a/external/Box2D/Collision/b2BroadPhase.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -using namespace std; - -b2BroadPhase::b2BroadPhase() -{ - m_proxyCount = 0; - - m_pairCapacity = 16; - m_pairCount = 0; - m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); - - m_moveCapacity = 16; - m_moveCount = 0; - m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); -} - -b2BroadPhase::~b2BroadPhase() -{ - b2Free(m_moveBuffer); - b2Free(m_pairBuffer); -} - -int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) -{ - int32 proxyId = m_tree.CreateProxy(aabb, userData); - ++m_proxyCount; - BufferMove(proxyId); - return proxyId; -} - -void b2BroadPhase::DestroyProxy(int32 proxyId) -{ - UnBufferMove(proxyId); - --m_proxyCount; - m_tree.DestroyProxy(proxyId); -} - -void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) -{ - bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); - if (buffer) - { - BufferMove(proxyId); - } -} - -void b2BroadPhase::TouchProxy(int32 proxyId) -{ - BufferMove(proxyId); -} - -void b2BroadPhase::BufferMove(int32 proxyId) -{ - if (m_moveCount == m_moveCapacity) - { - int32* oldBuffer = m_moveBuffer; - m_moveCapacity *= 2; - m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); - memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); - b2Free(oldBuffer); - } - - m_moveBuffer[m_moveCount] = proxyId; - ++m_moveCount; -} - -void b2BroadPhase::UnBufferMove(int32 proxyId) -{ - for (int32 i = 0; i < m_moveCount; ++i) - { - if (m_moveBuffer[i] == proxyId) - { - m_moveBuffer[i] = e_nullProxy; - return; - } - } -} - -// This is called from b2DynamicTree::Query when we are gathering pairs. -bool b2BroadPhase::QueryCallback(int32 proxyId) -{ - // A proxy cannot form a pair with itself. - if (proxyId == m_queryProxyId) - { - return true; - } - - // Grow the pair buffer as needed. - if (m_pairCount == m_pairCapacity) - { - b2Pair* oldBuffer = m_pairBuffer; - m_pairCapacity *= 2; - m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); - memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); - b2Free(oldBuffer); - } - - m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); - m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); - ++m_pairCount; - - return true; -} diff --git a/external/Box2D/Collision/b2BroadPhase.h b/external/Box2D/Collision/b2BroadPhase.h deleted file mode 100644 index cf2414730a..0000000000 --- a/external/Box2D/Collision/b2BroadPhase.h +++ /dev/null @@ -1,248 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_BROAD_PHASE_H -#define B2_BROAD_PHASE_H - -#include -#include -#include -#include - -struct b2Pair -{ - int32 proxyIdA; - int32 proxyIdB; - int32 next; -}; - -/// The broad-phase is used for computing pairs and performing volume queries and ray casts. -/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. -/// It is up to the client to consume the new pairs and to track subsequent overlap. -class b2BroadPhase -{ -public: - - enum - { - e_nullProxy = -1 - }; - - b2BroadPhase(); - ~b2BroadPhase(); - - /// Create a proxy with an initial AABB. Pairs are not reported until - /// UpdatePairs is called. - int32 CreateProxy(const b2AABB& aabb, void* userData); - - /// Destroy a proxy. It is up to the client to remove any pairs. - void DestroyProxy(int32 proxyId); - - /// Call MoveProxy as many times as you like, then when you are done - /// call UpdatePairs to finalized the proxy pairs (for your time step). - void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); - - /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. - void TouchProxy(int32 proxyId); - - /// Get the fat AABB for a proxy. - const b2AABB& GetFatAABB(int32 proxyId) const; - - /// Get user data from a proxy. Returns NULL if the id is invalid. - void* GetUserData(int32 proxyId) const; - - /// Test overlap of fat AABBs. - bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; - - /// Get the number of proxies. - int32 GetProxyCount() const; - - /// Update the pairs. This results in pair callbacks. This can only add pairs. - template - void UpdatePairs(T* callback); - - /// Query an AABB for overlapping proxies. The callback class - /// is called for each proxy that overlaps the supplied AABB. - template - void Query(T* callback, const b2AABB& aabb) const; - - /// Ray-cast against the proxies in the tree. This relies on the callback - /// to perform a exact ray-cast in the case were the proxy contains a shape. - /// The callback also performs the any collision filtering. This has performance - /// roughly equal to k * log(n), where k is the number of collisions and n is the - /// number of proxies in the tree. - /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). - /// @param callback a callback class that is called for each proxy that is hit by the ray. - template - void RayCast(T* callback, const b2RayCastInput& input) const; - - /// Get the height of the embedded tree. - int32 GetTreeHeight() const; - - /// Get the balance of the embedded tree. - int32 GetTreeBalance() const; - - /// Get the quality metric of the embedded tree. - float32 GetTreeQuality() const; - -private: - - friend class b2DynamicTree; - - void BufferMove(int32 proxyId); - void UnBufferMove(int32 proxyId); - - bool QueryCallback(int32 proxyId); - - b2DynamicTree m_tree; - - int32 m_proxyCount; - - int32* m_moveBuffer; - int32 m_moveCapacity; - int32 m_moveCount; - - b2Pair* m_pairBuffer; - int32 m_pairCapacity; - int32 m_pairCount; - - int32 m_queryProxyId; -}; - -/// This is used to sort pairs. -inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) -{ - if (pair1.proxyIdA < pair2.proxyIdA) - { - return true; - } - - if (pair1.proxyIdA == pair2.proxyIdA) - { - return pair1.proxyIdB < pair2.proxyIdB; - } - - return false; -} - -inline void* b2BroadPhase::GetUserData(int32 proxyId) const -{ - return m_tree.GetUserData(proxyId); -} - -inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const -{ - const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); - const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); - return b2TestOverlap(aabbA, aabbB); -} - -inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const -{ - return m_tree.GetFatAABB(proxyId); -} - -inline int32 b2BroadPhase::GetProxyCount() const -{ - return m_proxyCount; -} - -inline int32 b2BroadPhase::GetTreeHeight() const -{ - return m_tree.GetHeight(); -} - -inline int32 b2BroadPhase::GetTreeBalance() const -{ - return m_tree.GetMaxBalance(); -} - -inline float32 b2BroadPhase::GetTreeQuality() const -{ - return m_tree.GetAreaRatio(); -} - -template -void b2BroadPhase::UpdatePairs(T* callback) -{ - // Reset pair buffer - m_pairCount = 0; - - // Perform tree queries for all moving proxies. - for (int32 i = 0; i < m_moveCount; ++i) - { - m_queryProxyId = m_moveBuffer[i]; - if (m_queryProxyId == e_nullProxy) - { - continue; - } - - // We have to query the tree with the fat AABB so that - // we don't fail to create a pair that may touch later. - const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); - - // Query tree, create pairs and add them pair buffer. - m_tree.Query(this, fatAABB); - } - - // Reset move buffer - m_moveCount = 0; - - // Sort the pair buffer to expose duplicates. - std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); - - // Send the pairs back to the client. - int32 i = 0; - while (i < m_pairCount) - { - b2Pair* primaryPair = m_pairBuffer + i; - void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); - void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); - - callback->AddPair(userDataA, userDataB); - ++i; - - // Skip any duplicate pairs. - while (i < m_pairCount) - { - b2Pair* pair = m_pairBuffer + i; - if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) - { - break; - } - ++i; - } - } - - // Try to keep the tree balanced. - //m_tree.Rebalance(4); -} - -template -inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const -{ - m_tree.Query(callback, aabb); -} - -template -inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const -{ - m_tree.RayCast(callback, input); -} - -#endif diff --git a/external/Box2D/Collision/b2CollideCircle.cpp b/external/Box2D/Collision/b2CollideCircle.cpp deleted file mode 100644 index ed561eb04b..0000000000 --- a/external/Box2D/Collision/b2CollideCircle.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include - -void b2CollideCircles( - b2Manifold* manifold, - const b2CircleShape* circleA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - - b2Vec2 pA = b2Mul(xfA, circleA->m_p); - b2Vec2 pB = b2Mul(xfB, circleB->m_p); - - b2Vec2 d = pB - pA; - float32 distSqr = b2Dot(d, d); - float32 rA = circleA->m_radius, rB = circleB->m_radius; - float32 radius = rA + rB; - if (distSqr > radius * radius) - { - return; - } - - manifold->type = b2Manifold::e_circles; - manifold->localPoint = circleA->m_p; - manifold->localNormal.SetZero(); - manifold->pointCount = 1; - - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; -} - -void b2CollidePolygonAndCircle( - b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - - // Compute circle position in the frame of the polygon. - b2Vec2 c = b2Mul(xfB, circleB->m_p); - b2Vec2 cLocal = b2MulT(xfA, c); - - // Find the min separating edge. - int32 normalIndex = 0; - float32 separation = -b2_maxFloat; - float32 radius = polygonA->m_radius + circleB->m_radius; - int32 vertexCount = polygonA->m_vertexCount; - const b2Vec2* vertices = polygonA->m_vertices; - const b2Vec2* normals = polygonA->m_normals; - - for (int32 i = 0; i < vertexCount; ++i) - { - float32 s = b2Dot(normals[i], cLocal - vertices[i]); - - if (s > radius) - { - // Early out. - return; - } - - if (s > separation) - { - separation = s; - normalIndex = i; - } - } - - // Vertices that subtend the incident face. - int32 vertIndex1 = normalIndex; - int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; - b2Vec2 v1 = vertices[vertIndex1]; - b2Vec2 v2 = vertices[vertIndex2]; - - // If the center is inside the polygon ... - if (separation < b2_epsilon) - { - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = normals[normalIndex]; - manifold->localPoint = 0.5f * (v1 + v2); - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - return; - } - - // Compute barycentric coordinates - float32 u1 = b2Dot(cLocal - v1, v2 - v1); - float32 u2 = b2Dot(cLocal - v2, v1 - v2); - if (u1 <= 0.0f) - { - if (b2DistanceSquared(cLocal, v1) > radius * radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = cLocal - v1; - manifold->localNormal.Normalize(); - manifold->localPoint = v1; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } - else if (u2 <= 0.0f) - { - if (b2DistanceSquared(cLocal, v2) > radius * radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = cLocal - v2; - manifold->localNormal.Normalize(); - manifold->localPoint = v2; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } - else - { - b2Vec2 faceCenter = 0.5f * (v1 + v2); - float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); - if (separation > radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = normals[vertIndex1]; - manifold->localPoint = faceCenter; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } -} diff --git a/external/Box2D/Collision/b2CollideEdge.cpp b/external/Box2D/Collision/b2CollideEdge.cpp deleted file mode 100644 index 96ca71dccc..0000000000 --- a/external/Box2D/Collision/b2CollideEdge.cpp +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include -#include -#include -#include - - -// 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 hasVertex3F = 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 (hasVertex3F) - { - 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 && hasVertex3F) - { - 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 (hasVertex3F) - { - 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 = 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 = 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 = 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 = 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); -} diff --git a/external/Box2D/Collision/b2CollidePolygon.cpp b/external/Box2D/Collision/b2CollidePolygon.cpp deleted file mode 100644 index be2518d966..0000000000 --- a/external/Box2D/Collision/b2CollidePolygon.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -// Find the separation between poly1 and poly2 for a give edge normal on poly1. -static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - const b2Vec2* vertices1 = poly1->m_vertices; - const b2Vec2* normals1 = poly1->m_normals; - - int32 count2 = poly2->m_vertexCount; - const b2Vec2* vertices2 = poly2->m_vertices; - - b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); - - // Convert normal from poly1's frame into poly2's frame. - b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); - b2Vec2 normal1 = b2MulT(xf2.q, normal1World); - - // Find support vertex on poly2 for -normal. - int32 index = 0; - float32 minDot = b2_maxFloat; - - for (int32 i = 0; i < count2; ++i) - { - float32 dot = b2Dot(vertices2[i], normal1); - if (dot < minDot) - { - minDot = dot; - index = i; - } - } - - b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); - b2Vec2 v2 = b2Mul(xf2, vertices2[index]); - float32 separation = b2Dot(v2 - v1, normal1World); - return separation; -} - -// Find the max separation between poly1 and poly2 using edge normals from poly1. -static float32 b2FindMaxSeparation(int32* edgeIndex, - const b2PolygonShape* poly1, const b2Transform& xf1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - int32 count1 = poly1->m_vertexCount; - const b2Vec2* normals1 = poly1->m_normals; - - // Vector pointing from the centroid of poly1 to the centroid of poly2. - b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); - b2Vec2 dLocal1 = b2MulT(xf1.q, d); - - // Find edge normal on poly1 that has the largest projection onto d. - int32 edge = 0; - float32 maxDot = -b2_maxFloat; - for (int32 i = 0; i < count1; ++i) - { - float32 dot = b2Dot(normals1[i], dLocal1); - if (dot > maxDot) - { - maxDot = dot; - edge = i; - } - } - - // Get the separation for the edge normal. - float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); - - // Check the separation for the previous edge normal. - int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; - float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); - - // Check the separation for the next edge normal. - int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; - float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); - - // Find the best edge and the search direction. - int32 bestEdge; - float32 bestSeparation; - int32 increment; - if (sPrev > s && sPrev > sNext) - { - increment = -1; - bestEdge = prevEdge; - bestSeparation = sPrev; - } - else if (sNext > s) - { - increment = 1; - bestEdge = nextEdge; - bestSeparation = sNext; - } - else - { - *edgeIndex = edge; - return s; - } - - // Perform a local search for the best edge normal. - for ( ; ; ) - { - if (increment == -1) - edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; - else - edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; - - s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); - - if (s > bestSeparation) - { - bestEdge = edge; - bestSeparation = s; - } - else - { - break; - } - } - - *edgeIndex = bestEdge; - return bestSeparation; -} - -static void b2FindIncidentEdge(b2ClipVertex c[2], - const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - const b2Vec2* normals1 = poly1->m_normals; - - int32 count2 = poly2->m_vertexCount; - const b2Vec2* vertices2 = poly2->m_vertices; - const b2Vec2* normals2 = poly2->m_normals; - - b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); - - // Get the normal of the reference edge in poly2's frame. - b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); - - // Find the incident edge on poly2. - int32 index = 0; - float32 minDot = b2_maxFloat; - for (int32 i = 0; i < count2; ++i) - { - float32 dot = b2Dot(normal1, normals2[i]); - if (dot < minDot) - { - minDot = dot; - index = i; - } - } - - // Build the clip vertices for the incident edge. - int32 i1 = index; - int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; - - c[0].v = b2Mul(xf2, vertices2[i1]); - c[0].id.cf.indexA = (uint8)edge1; - c[0].id.cf.indexB = (uint8)i1; - c[0].id.cf.typeA = b2ContactFeature::e_face; - c[0].id.cf.typeB = b2ContactFeature::e_vertex; - - c[1].v = b2Mul(xf2, vertices2[i2]); - c[1].id.cf.indexA = (uint8)edge1; - c[1].id.cf.indexB = (uint8)i2; - c[1].id.cf.typeA = b2ContactFeature::e_face; - c[1].id.cf.typeB = b2ContactFeature::e_vertex; -} - -// Find edge normal of max separation on A - return if separating axis is found -// Find edge normal of max separation on B - return if separation axis is found -// Choose reference edge as min(minA, minB) -// Find incident edge -// Clip - -// The normal points from 1 to 2 -void b2CollidePolygons(b2Manifold* manifold, - const b2PolygonShape* polyA, const b2Transform& xfA, - const b2PolygonShape* polyB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - float32 totalRadius = polyA->m_radius + polyB->m_radius; - - int32 edgeA = 0; - float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); - if (separationA > totalRadius) - return; - - int32 edgeB = 0; - float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); - if (separationB > totalRadius) - return; - - const b2PolygonShape* poly1; // reference polygon - const b2PolygonShape* poly2; // incident polygon - b2Transform xf1, xf2; - int32 edge1; // reference edge - uint8 flip; - const float32 k_relativeTol = 0.98f; - const float32 k_absoluteTol = 0.001f; - - if (separationB > k_relativeTol * separationA + k_absoluteTol) - { - poly1 = polyB; - poly2 = polyA; - xf1 = xfB; - xf2 = xfA; - edge1 = edgeB; - manifold->type = b2Manifold::e_faceB; - flip = 1; - } - else - { - poly1 = polyA; - poly2 = polyB; - xf1 = xfA; - xf2 = xfB; - edge1 = edgeA; - manifold->type = b2Manifold::e_faceA; - flip = 0; - } - - b2ClipVertex incidentEdge[2]; - b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); - - int32 count1 = poly1->m_vertexCount; - const b2Vec2* vertices1 = poly1->m_vertices; - - int32 iv1 = edge1; - int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; - - b2Vec2 v11 = vertices1[iv1]; - b2Vec2 v12 = vertices1[iv2]; - - b2Vec2 localTangent = v12 - v11; - localTangent.Normalize(); - - b2Vec2 localNormal = b2Cross(localTangent, 1.0f); - b2Vec2 planePoint = 0.5f * (v11 + v12); - - b2Vec2 tangent = b2Mul(xf1.q, localTangent); - b2Vec2 normal = b2Cross(tangent, 1.0f); - - v11 = b2Mul(xf1, v11); - v12 = b2Mul(xf1, v12); - - // Face offset. - float32 frontOffset = b2Dot(normal, v11); - - // Side offsets, extended by polytope skin thickness. - float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; - float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; - - // Clip incident edge against extruded edge1 side edges. - b2ClipVertex clipPoints1[2]; - b2ClipVertex clipPoints2[2]; - int np; - - // Clip to box side 1 - np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); - - if (np < 2) - return; - - // Clip to negative box side 1 - np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); - - if (np < 2) - { - return; - } - - // Now clipPoints2 contains the clipped points. - manifold->localNormal = localNormal; - manifold->localPoint = planePoint; - - int32 pointCount = 0; - for (int32 i = 0; i < b2_maxManifoldPoints; ++i) - { - float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; - - if (separation <= totalRadius) - { - b2ManifoldPoint* cp = manifold->points + pointCount; - cp->localPoint = b2MulT(xf2, clipPoints2[i].v); - cp->id = clipPoints2[i].id; - if (flip) - { - // Swap features - b2ContactFeature cf = cp->id.cf; - cp->id.cf.indexA = cf.indexB; - cp->id.cf.indexB = cf.indexA; - cp->id.cf.typeA = cf.typeB; - cp->id.cf.typeB = cf.typeA; - } - ++pointCount; - } - } - - manifold->pointCount = pointCount; -} diff --git a/external/Box2D/Collision/b2Collision.cpp b/external/Box2D/Collision/b2Collision.cpp deleted file mode 100644 index 2dd5ff0ab6..0000000000 --- a/external/Box2D/Collision/b2Collision.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include - -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 = 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; -} diff --git a/external/Box2D/Collision/b2Collision.h b/external/Box2D/Collision/b2Collision.h deleted file mode 100644 index 2e7386232b..0000000000 --- a/external/Box2D/Collision/b2Collision.h +++ /dev/null @@ -1,276 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_COLLISION_H -#define B2_COLLISION_H - -#include -#include - -/// @file -/// Structures and functions used for computing contact points, distance -/// queries, and TOI queries. - -class b2Shape; -class b2CircleShape; -class b2EdgeShape; -class b2PolygonShape; - -const uint8 b2_nullFeature = UCHAR_MAX; - -/// The features that intersect to form the contact point -/// This must be 4 bytes or less. -struct b2ContactFeature -{ - enum Type - { - e_vertex = 0, - e_face = 1 - }; - - uint8 indexA; ///< Feature index on shapeA - uint8 indexB; ///< Feature index on shapeB - uint8 typeA; ///< The feature type on shapeA - uint8 typeB; ///< The feature type on shapeB -}; - -/// Contact ids to facilitate warm starting. -union b2ContactID -{ - b2ContactFeature cf; - uint32 key; ///< Used to quickly compare contact ids. -}; - -/// A manifold point is a contact point belonging to a contact -/// manifold. It holds details related to the geometry and dynamics -/// of the contact points. -/// The local point usage depends on the manifold type: -/// -e_circles: the local center of circleB -/// -e_faceA: the local center of cirlceB or the clip point of polygonB -/// -e_faceB: the clip point of polygonA -/// This structure is stored across time steps, so we keep it small. -/// Note: the impulses are used for internal caching and may not -/// provide reliable contact forces, especially for high speed collisions. -struct b2ManifoldPoint -{ - b2Vec2 localPoint; ///< usage depends on manifold type - float32 normalImpulse; ///< the non-penetration impulse - float32 tangentImpulse; ///< the friction impulse - b2ContactID id; ///< uniquely identifies a contact point between two shapes -}; - -/// A manifold for two touching convex shapes. -/// Box2D supports multiple types of contact: -/// - clip point versus plane with radius -/// - point versus point with radius (circles) -/// The local point usage depends on the manifold type: -/// -e_circles: the local center of circleA -/// -e_faceA: the center of faceA -/// -e_faceB: the center of faceB -/// Similarly the local normal usage: -/// -e_circles: not used -/// -e_faceA: the normal on polygonA -/// -e_faceB: the normal on polygonB -/// We store contacts in this way so that position correction can -/// account for movement, which is critical for continuous physics. -/// All contact scenarios must be expressed in one of these types. -/// This structure is stored across time steps, so we keep it small. -struct b2Manifold -{ - enum Type - { - e_circles, - e_faceA, - e_faceB - }; - - b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact - b2Vec2 localNormal; ///< not use for Type::e_points - b2Vec2 localPoint; ///< usage depends on manifold type - Type type; - int32 pointCount; ///< the number of manifold points -}; - -/// This is used to compute the current state of a contact manifold. -struct b2WorldManifold -{ - /// Evaluate the manifold with supplied transforms. This assumes - /// modest motion from the original state. This does not change the - /// point count, impulses, etc. The radii must come from the shapes - /// that generated the manifold. - void Initialize(const b2Manifold* manifold, - const b2Transform& xfA, float32 radiusA, - const b2Transform& xfB, float32 radiusB); - - b2Vec2 normal; ///< world vector pointing from A to B - b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) -}; - -/// This is used for determining the state of contact points. -enum b2PointState -{ - b2_nullState, ///< point does not exist - b2_addState, ///< point was added in the update - b2_persistState, ///< point persisted across the update - b2_removeState ///< point was removed in the update -}; - -/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 -/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. -void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], - const b2Manifold* manifold1, const b2Manifold* manifold2); - -/// Used for computing contact manifolds. -struct b2ClipVertex -{ - b2Vec2 v; - b2ContactID id; -}; - -/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). -struct b2RayCastInput -{ - b2Vec2 p1, p2; - float32 maxFraction; -}; - -/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 -/// come from b2RayCastInput. -struct b2RayCastOutput -{ - b2Vec2 normal; - float32 fraction; -}; - -/// An axis aligned bounding box. -struct b2AABB -{ - /// Verify that the bounds are sorted. - bool IsValid() const; - - /// Get the center of the AABB. - b2Vec2 GetCenter() const - { - return 0.5f * (lowerBound + upperBound); - } - - /// Get the extents of the AABB (half-widths). - b2Vec2 GetExtents() const - { - return 0.5f * (upperBound - lowerBound); - } - - /// Get the perimeter length - float32 GetPerimeter() const - { - float32 wx = upperBound.x - lowerBound.x; - float32 wy = upperBound.y - lowerBound.y; - return 2.0f * (wx + wy); - } - - /// Combine an AABB into this one. - void Combine(const b2AABB& aabb) - { - lowerBound = b2Min(lowerBound, aabb.lowerBound); - upperBound = b2Max(upperBound, aabb.upperBound); - } - - /// Combine two AABBs into this one. - void Combine(const b2AABB& aabb1, const b2AABB& aabb2) - { - lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); - upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); - } - - /// Does this aabb contain the provided AABB. - bool Contains(const b2AABB& aabb) const - { - bool result = true; - result = result && lowerBound.x <= aabb.lowerBound.x; - result = result && lowerBound.y <= aabb.lowerBound.y; - result = result && aabb.upperBound.x <= upperBound.x; - result = result && aabb.upperBound.y <= upperBound.y; - return result; - } - - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; - - b2Vec2 lowerBound; ///< the lower vertex - b2Vec2 upperBound; ///< the upper vertex -}; - -/// Compute the collision manifold between two circles. -void b2CollideCircles(b2Manifold* manifold, - const b2CircleShape* circleA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between a polygon and a circle. -void b2CollidePolygonAndCircle(b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between two polygons. -void b2CollidePolygons(b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2PolygonShape* polygonB, const b2Transform& xfB); - -/// Compute the collision manifold between an edge and a circle. -void b2CollideEdgeAndCircle(b2Manifold* manifold, - const b2EdgeShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between an edge and a circle. -void b2CollideEdgeAndPolygon(b2Manifold* manifold, - const b2EdgeShape* edgeA, const b2Transform& xfA, - const b2PolygonShape* circleB, const b2Transform& xfB); - -/// Clipping for contact manifolds. -int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], - const b2Vec2& normal, float32 offset, int32 vertexIndexA); - -/// Determine if two generic shapes overlap. -bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, - const b2Shape* shapeB, int32 indexB, - const b2Transform& xfA, const b2Transform& xfB); - -// ---------------- Inline Functions ------------------------------------------ - -inline bool b2AABB::IsValid() const -{ - b2Vec2 d = upperBound - lowerBound; - bool valid = d.x >= 0.0f && d.y >= 0.0f; - valid = valid && lowerBound.IsValid() && upperBound.IsValid(); - return valid; -} - -inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) -{ - b2Vec2 d1, d2; - d1 = b.lowerBound - a.upperBound; - d2 = a.lowerBound - b.upperBound; - - if (d1.x > 0.0f || d1.y > 0.0f) - return false; - - if (d2.x > 0.0f || d2.y > 0.0f) - return false; - - return true; -} - -#endif diff --git a/external/Box2D/Collision/b2Distance.cpp b/external/Box2D/Collision/b2Distance.cpp deleted file mode 100644 index ac67d3be43..0000000000 --- a/external/Box2D/Collision/b2Distance.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include -#include -#include - -// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. -int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; - -void b2DistanceProxy::Set(const b2Shape* shape, int32 index) -{ - switch (shape->GetType()) - { - case b2Shape::e_circle: - { - const b2CircleShape* circle = (b2CircleShape*)shape; - m_vertices = &circle->m_p; - m_count = 1; - m_radius = circle->m_radius; - } - break; - - case b2Shape::e_polygon: - { - const b2PolygonShape* polygon = (b2PolygonShape*)shape; - m_vertices = polygon->m_vertices; - m_count = polygon->m_vertexCount; - m_radius = polygon->m_radius; - } - break; - - case b2Shape::e_chain: - { - const b2ChainShape* chain = (b2ChainShape*)shape; - b2Assert(0 <= index && index < chain->m_count); - - m_buffer[0] = chain->m_vertices[index]; - if (index + 1 < chain->m_count) - { - m_buffer[1] = chain->m_vertices[index + 1]; - } - else - { - m_buffer[1] = chain->m_vertices[0]; - } - - m_vertices = m_buffer; - m_count = 2; - m_radius = chain->m_radius; - } - break; - - case b2Shape::e_edge: - { - const b2EdgeShape* edge = (b2EdgeShape*)shape; - m_vertices = &edge->m_vertex1; - m_count = 2; - m_radius = edge->m_radius; - } - break; - - default: - b2Assert(false); - } -} - - -struct b2SimplexVertex -{ - b2Vec2 wA; // support point in proxyA - b2Vec2 wB; // support point in proxyB - b2Vec2 w; // wB - wA - float32 a; // barycentric coordinate for closest point - int32 indexA; // wA index - int32 indexB; // wB index -}; - -struct b2Simplex -{ - void ReadCache( const b2SimplexCache* cache, - const b2DistanceProxy* proxyA, const b2Transform& transformA, - const b2DistanceProxy* proxyB, const b2Transform& transformB) - { - b2Assert(cache->count <= 3); - - // Copy data from cache. - m_count = cache->count; - b2SimplexVertex* vertices = &m_v1; - for (int32 i = 0; i < m_count; ++i) - { - b2SimplexVertex* v = vertices + i; - v->indexA = cache->indexA[i]; - v->indexB = cache->indexB[i]; - b2Vec2 wALocal = proxyA->GetVertex(v->indexA); - b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); - v->wA = b2Mul(transformA, wALocal); - v->wB = b2Mul(transformB, wBLocal); - v->w = v->wB - v->wA; - v->a = 0.0f; - } - - // Compute the new simplex metric, if it is substantially different than - // old metric then flush the simplex. - if (m_count > 1) - { - float32 metric1 = cache->metric; - float32 metric2 = GetMetric(); - if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) - { - // Reset the simplex. - m_count = 0; - } - } - - // If the cache is empty or invalid ... - if (m_count == 0) - { - b2SimplexVertex* v = vertices + 0; - v->indexA = 0; - v->indexB = 0; - b2Vec2 wALocal = proxyA->GetVertex(0); - b2Vec2 wBLocal = proxyB->GetVertex(0); - v->wA = b2Mul(transformA, wALocal); - v->wB = b2Mul(transformB, wBLocal); - v->w = v->wB - v->wA; - m_count = 1; - } - } - - void WriteCache(b2SimplexCache* cache) const - { - cache->metric = GetMetric(); - cache->count = uint16(m_count); - const b2SimplexVertex* vertices = &m_v1; - for (int32 i = 0; i < m_count; ++i) - { - cache->indexA[i] = uint8(vertices[i].indexA); - cache->indexB[i] = uint8(vertices[i].indexB); - } - } - - b2Vec2 GetSearchDirection() const - { - switch (m_count) - { - case 1: - return -m_v1.w; - - case 2: - { - b2Vec2 e12 = m_v2.w - m_v1.w; - float32 sgn = b2Cross(e12, -m_v1.w); - if (sgn > 0.0f) - { - // Origin is left of e12. - return b2Cross(1.0f, e12); - } - else - { - // Origin is right of e12. - return b2Cross(e12, 1.0f); - } - } - - default: - b2Assert(false); - return b2Vec2_zero; - } - } - - b2Vec2 GetClosestPoint() const - { - switch (m_count) - { - case 0: - b2Assert(false); - return b2Vec2_zero; - - case 1: - return m_v1.w; - - case 2: - return m_v1.a * m_v1.w + m_v2.a * m_v2.w; - - case 3: - return b2Vec2_zero; - - default: - b2Assert(false); - return b2Vec2_zero; - } - } - - void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const - { - switch (m_count) - { - case 0: - b2Assert(false); - break; - - case 1: - *pA = m_v1.wA; - *pB = m_v1.wB; - break; - - case 2: - *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; - *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; - break; - - case 3: - *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; - *pB = *pA; - break; - - default: - b2Assert(false); - break; - } - } - - float32 GetMetric() const - { - switch (m_count) - { - case 0: - b2Assert(false); - return 0.0; - - case 1: - return 0.0f; - - case 2: - return b2Distance(m_v1.w, m_v2.w); - - case 3: - return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); - - default: - b2Assert(false); - return 0.0f; - } - } - - void Solve2(); - void Solve3(); - - b2SimplexVertex m_v1, m_v2, m_v3; - int32 m_count; -}; - - -// Solve a line segment using barycentric coordinates. -// -// p = a1 * w1 + a2 * w2 -// a1 + a2 = 1 -// -// The vector from the origin to the closest point on the line is -// perpendicular to the line. -// e12 = w2 - w1 -// dot(p, e) = 0 -// a1 * dot(w1, e) + a2 * dot(w2, e) = 0 -// -// 2-by-2 linear system -// [1 1 ][a1] = [1] -// [w1.e12 w2.e12][a2] = [0] -// -// Define -// d12_1 = dot(w2, e12) -// d12_2 = -dot(w1, e12) -// d12 = d12_1 + d12_2 -// -// Solution -// a1 = d12_1 / d12 -// a2 = d12_2 / d12 -void b2Simplex::Solve2() -{ - b2Vec2 w1 = m_v1.w; - b2Vec2 w2 = m_v2.w; - b2Vec2 e12 = w2 - w1; - - // w1 region - float32 d12_2 = -b2Dot(w1, e12); - if (d12_2 <= 0.0f) - { - // a2 <= 0, so we clamp it to 0 - m_v1.a = 1.0f; - m_count = 1; - return; - } - - // w2 region - float32 d12_1 = b2Dot(w2, e12); - if (d12_1 <= 0.0f) - { - // a1 <= 0, so we clamp it to 0 - m_v2.a = 1.0f; - m_count = 1; - m_v1 = m_v2; - return; - } - - // Must be in e12 region. - float32 inv_d12 = 1.0f / (d12_1 + d12_2); - m_v1.a = d12_1 * inv_d12; - m_v2.a = d12_2 * inv_d12; - m_count = 2; -} - -// Possible regions: -// - points[2] -// - edge points[0]-points[2] -// - edge points[1]-points[2] -// - inside the triangle -void b2Simplex::Solve3() -{ - b2Vec2 w1 = m_v1.w; - b2Vec2 w2 = m_v2.w; - b2Vec2 w3 = m_v3.w; - - // Edge12 - // [1 1 ][a1] = [1] - // [w1.e12 w2.e12][a2] = [0] - // a3 = 0 - b2Vec2 e12 = w2 - w1; - float32 w1e12 = b2Dot(w1, e12); - float32 w2e12 = b2Dot(w2, e12); - float32 d12_1 = w2e12; - float32 d12_2 = -w1e12; - - // Edge13 - // [1 1 ][a1] = [1] - // [w1.e13 w3.e13][a3] = [0] - // a2 = 0 - b2Vec2 e13 = w3 - w1; - float32 w1e13 = b2Dot(w1, e13); - float32 w3e13 = b2Dot(w3, e13); - float32 d13_1 = w3e13; - float32 d13_2 = -w1e13; - - // Edge23 - // [1 1 ][a2] = [1] - // [w2.e23 w3.e23][a3] = [0] - // a1 = 0 - b2Vec2 e23 = w3 - w2; - float32 w2e23 = b2Dot(w2, e23); - float32 w3e23 = b2Dot(w3, e23); - float32 d23_1 = w3e23; - float32 d23_2 = -w2e23; - - // Triangle123 - float32 n123 = b2Cross(e12, e13); - - float32 d123_1 = n123 * b2Cross(w2, w3); - float32 d123_2 = n123 * b2Cross(w3, w1); - float32 d123_3 = n123 * b2Cross(w1, w2); - - // w1 region - if (d12_2 <= 0.0f && d13_2 <= 0.0f) - { - m_v1.a = 1.0f; - m_count = 1; - return; - } - - // e12 - if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) - { - float32 inv_d12 = 1.0f / (d12_1 + d12_2); - m_v1.a = d12_1 * inv_d12; - m_v2.a = d12_2 * inv_d12; - m_count = 2; - return; - } - - // e13 - if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) - { - float32 inv_d13 = 1.0f / (d13_1 + d13_2); - m_v1.a = d13_1 * inv_d13; - m_v3.a = d13_2 * inv_d13; - m_count = 2; - m_v2 = m_v3; - return; - } - - // w2 region - if (d12_1 <= 0.0f && d23_2 <= 0.0f) - { - m_v2.a = 1.0f; - m_count = 1; - m_v1 = m_v2; - return; - } - - // w3 region - if (d13_1 <= 0.0f && d23_1 <= 0.0f) - { - m_v3.a = 1.0f; - m_count = 1; - m_v1 = m_v3; - return; - } - - // e23 - if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) - { - float32 inv_d23 = 1.0f / (d23_1 + d23_2); - m_v2.a = d23_1 * inv_d23; - m_v3.a = d23_2 * inv_d23; - m_count = 2; - m_v1 = m_v3; - return; - } - - // Must be in triangle123 - float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); - m_v1.a = d123_1 * inv_d123; - m_v2.a = d123_2 * inv_d123; - m_v3.a = d123_3 * inv_d123; - m_count = 3; -} - -void b2Distance(b2DistanceOutput* output, - b2SimplexCache* cache, - const b2DistanceInput* input) -{ - ++b2_gjkCalls; - - const b2DistanceProxy* proxyA = &input->proxyA; - const b2DistanceProxy* proxyB = &input->proxyB; - - b2Transform transformA = input->transformA; - b2Transform transformB = input->transformB; - - // Initialize the simplex. - b2Simplex simplex; - simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); - - // Get simplex vertices as an array. - b2SimplexVertex* vertices = &simplex.m_v1; - const int32 k_maxIters = 20; - - // These store the vertices of the last simplex so that we - // can check for duplicates and prevent cycling. - int32 saveA[3], saveB[3]; - int32 saveCount = 0; - - b2Vec2 closestPoint = simplex.GetClosestPoint(); - float32 distanceSqr1 = closestPoint.LengthSquared(); - float32 distanceSqr2 = distanceSqr1; - - // Main iteration loop. - int32 iter = 0; - while (iter < k_maxIters) - { - // Copy simplex so we can identify duplicates. - saveCount = simplex.m_count; - for (int32 i = 0; i < saveCount; ++i) - { - saveA[i] = vertices[i].indexA; - saveB[i] = vertices[i].indexB; - } - - switch (simplex.m_count) - { - case 1: - break; - - case 2: - simplex.Solve2(); - break; - - case 3: - simplex.Solve3(); - break; - - default: - b2Assert(false); - } - - // If we have 3 points, then the origin is in the corresponding triangle. - if (simplex.m_count == 3) - { - break; - } - - // Compute closest point. - b2Vec2 p = simplex.GetClosestPoint(); - distanceSqr2 = p.LengthSquared(); - - // Ensure progress - if (distanceSqr2 >= distanceSqr1) - { - //break; - } - distanceSqr1 = distanceSqr2; - - // Get search direction. - b2Vec2 d = simplex.GetSearchDirection(); - - // Ensure the search direction is numerically fit. - if (d.LengthSquared() < b2_epsilon * b2_epsilon) - { - // The origin is probably contained by a line segment - // or triangle. Thus the shapes are overlapped. - - // We can't return zero here even though there may be overlap. - // In case the simplex is a point, segment, or triangle it is difficult - // to determine if the origin is contained in the CSO or very close to it. - break; - } - - // Compute a tentative new simplex vertex using support points. - b2SimplexVertex* vertex = vertices + simplex.m_count; - vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); - vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); - b2Vec2 wBLocal; - vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); - vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); - vertex->w = vertex->wB - vertex->wA; - - // Iteration count is equated to the number of support point calls. - ++iter; - ++b2_gjkIters; - - // Check for duplicate support points. This is the main termination criteria. - bool duplicate = false; - for (int32 i = 0; i < saveCount; ++i) - { - if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) - { - duplicate = true; - break; - } - } - - // If we found a duplicate support point we must exit to avoid cycling. - if (duplicate) - { - break; - } - - // New vertex is ok and needed. - ++simplex.m_count; - } - - b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); - - // Prepare output. - simplex.GetWitnessPoints(&output->pointA, &output->pointB); - output->distance = b2Distance(output->pointA, output->pointB); - output->iterations = iter; - - // Cache the simplex. - simplex.WriteCache(cache); - - // Apply radii if requested. - if (input->useRadii) - { - float32 rA = proxyA->m_radius; - float32 rB = proxyB->m_radius; - - if (output->distance > rA + rB && output->distance > b2_epsilon) - { - // Shapes are still no overlapped. - // Move the witness points to the outer surface. - output->distance -= rA + rB; - b2Vec2 normal = output->pointB - output->pointA; - normal.Normalize(); - output->pointA += rA * normal; - output->pointB -= rB * normal; - } - else - { - // Shapes are overlapped when radii are considered. - // Move the witness points to the middle. - b2Vec2 p = 0.5f * (output->pointA + output->pointB); - output->pointA = p; - output->pointB = p; - output->distance = 0.0f; - } - } -} diff --git a/external/Box2D/Collision/b2Distance.h b/external/Box2D/Collision/b2Distance.h deleted file mode 100644 index d598b7339d..0000000000 --- a/external/Box2D/Collision/b2Distance.h +++ /dev/null @@ -1,141 +0,0 @@ - -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_DISTANCE_H -#define B2_DISTANCE_H - -#include - -class b2Shape; - -/// A distance proxy is used by the GJK algorithm. -/// It encapsulates any shape. -struct b2DistanceProxy -{ - b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} - - /// Initialize the proxy using the given shape. The shape - /// must remain in scope while the proxy is in use. - void Set(const b2Shape* shape, int32 index); - - /// Get the supporting vertex index in the given direction. - int32 GetSupport(const b2Vec2& d) const; - - /// Get the supporting vertex in the given direction. - const b2Vec2& GetSupportVertex(const b2Vec2& d) const; - - /// Get the vertex count. - int32 GetVertexCount() const; - - /// Get a vertex by index. Used by b2Distance. - const b2Vec2& GetVertex(int32 index) const; - - b2Vec2 m_buffer[2]; - const b2Vec2* m_vertices; - int32 m_count; - float32 m_radius; -}; - -/// Used to warm start b2Distance. -/// Set count to zero on first call. -struct b2SimplexCache -{ - float32 metric; ///< length or area - uint16 count; - uint8 indexA[3]; ///< vertices on shape A - uint8 indexB[3]; ///< vertices on shape B -}; - -/// Input for b2Distance. -/// You have to option to use the shape radii -/// in the computation. Even -struct b2DistanceInput -{ - b2DistanceProxy proxyA; - b2DistanceProxy proxyB; - b2Transform transformA; - b2Transform transformB; - bool useRadii; -}; - -/// Output for b2Distance. -struct b2DistanceOutput -{ - b2Vec2 pointA; ///< closest point on shapeA - b2Vec2 pointB; ///< closest point on shapeB - float32 distance; - int32 iterations; ///< number of GJK iterations used -}; - -/// Compute the closest points between two shapes. Supports any combination of: -/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. -/// On the first call set b2SimplexCache.count to zero. -void b2Distance(b2DistanceOutput* output, - b2SimplexCache* cache, - const b2DistanceInput* input); - - -////////////////////////////////////////////////////////////////////////// - -inline int32 b2DistanceProxy::GetVertexCount() const -{ - return m_count; -} - -inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const -{ - b2Assert(0 <= index && index < m_count); - return m_vertices[index]; -} - -inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const -{ - int32 bestIndex = 0; - float32 bestValue = b2Dot(m_vertices[0], d); - for (int32 i = 1; i < m_count; ++i) - { - float32 value = b2Dot(m_vertices[i], d); - if (value > bestValue) - { - bestIndex = i; - bestValue = value; - } - } - - return bestIndex; -} - -inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const -{ - int32 bestIndex = 0; - float32 bestValue = b2Dot(m_vertices[0], d); - for (int32 i = 1; i < m_count; ++i) - { - float32 value = b2Dot(m_vertices[i], d); - if (value > bestValue) - { - bestIndex = i; - bestValue = value; - } - } - - return m_vertices[bestIndex]; -} - -#endif diff --git a/external/Box2D/Collision/b2DynamicTree.cpp b/external/Box2D/Collision/b2DynamicTree.cpp deleted file mode 100644 index d1d53297e2..0000000000 --- a/external/Box2D/Collision/b2DynamicTree.cpp +++ /dev/null @@ -1,775 +0,0 @@ -/* -* Copyright (c) 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 -#include -#ifndef SHP -#include -#else -#include -#endif -using namespace std; - - -b2DynamicTree::b2DynamicTree() -{ - m_root = b2_nullNode; - - m_nodeCapacity = 16; - m_nodeCount = 0; - m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); - memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); - - // Build a linked list for the free list. - for (int32 i = 0; i < m_nodeCapacity - 1; ++i) - { - m_nodes[i].next = i + 1; - m_nodes[i].height = -1; - } - m_nodes[m_nodeCapacity-1].next = b2_nullNode; - m_nodes[m_nodeCapacity-1].height = -1; - m_freeList = 0; - - m_path = 0; - - m_insertionCount = 0; -} - -b2DynamicTree::~b2DynamicTree() -{ - // This frees the entire tree in one shot. - b2Free(m_nodes); -} - -// Allocate a node from the pool. Grow the pool if necessary. -int32 b2DynamicTree::AllocateNode() -{ - // Expand the node pool as needed. - if (m_freeList == b2_nullNode) - { - b2Assert(m_nodeCount == m_nodeCapacity); - - // The free list is empty. Rebuild a bigger pool. - b2TreeNode* oldNodes = m_nodes; - m_nodeCapacity *= 2; - m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); - memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); - b2Free(oldNodes); - - // Build a linked list for the free list. The parent - // pointer becomes the "next" pointer. - for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) - { - m_nodes[i].next = i + 1; - m_nodes[i].height = -1; - } - m_nodes[m_nodeCapacity-1].next = b2_nullNode; - m_nodes[m_nodeCapacity-1].height = -1; - m_freeList = m_nodeCount; - } - - // Peel a node off the free list. - int32 nodeId = m_freeList; - m_freeList = m_nodes[nodeId].next; - m_nodes[nodeId].parent = b2_nullNode; - m_nodes[nodeId].child1 = b2_nullNode; - m_nodes[nodeId].child2 = b2_nullNode; - m_nodes[nodeId].height = 0; - m_nodes[nodeId].userData = NULL; - ++m_nodeCount; - return nodeId; -} - -// Return a node to the pool. -void b2DynamicTree::FreeNode(int32 nodeId) -{ - b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); - b2Assert(0 < m_nodeCount); - m_nodes[nodeId].next = m_freeList; - m_nodes[nodeId].height = -1; - m_freeList = nodeId; - --m_nodeCount; -} - -// Create a proxy in the tree as a leaf node. We return the index -// of the node instead of a pointer so that we can grow -// the node pool. -int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) -{ - int32 proxyId = AllocateNode(); - - // Fatten the aabb. - b2Vec2 r(b2_aabbExtension, b2_aabbExtension); - m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; - m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; - m_nodes[proxyId].userData = userData; - m_nodes[proxyId].height = 0; - - InsertLeaf(proxyId); - - return proxyId; -} - -void b2DynamicTree::DestroyProxy(int32 proxyId) -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - b2Assert(m_nodes[proxyId].IsLeaf()); - - RemoveLeaf(proxyId); - FreeNode(proxyId); -} - -bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - - b2Assert(m_nodes[proxyId].IsLeaf()); - - if (m_nodes[proxyId].aabb.Contains(aabb)) - { - return false; - } - - RemoveLeaf(proxyId); - - // Extend AABB. - b2AABB b = aabb; - b2Vec2 r(b2_aabbExtension, b2_aabbExtension); - b.lowerBound = b.lowerBound - r; - b.upperBound = b.upperBound + r; - - // Predict AABB displacement. - b2Vec2 d = b2_aabbMultiplier * displacement; - - if (d.x < 0.0f) - { - b.lowerBound.x += d.x; - } - else - { - b.upperBound.x += d.x; - } - - if (d.y < 0.0f) - { - b.lowerBound.y += d.y; - } - else - { - b.upperBound.y += d.y; - } - - m_nodes[proxyId].aabb = b; - - InsertLeaf(proxyId); - return true; -} - -void b2DynamicTree::InsertLeaf(int32 leaf) -{ - ++m_insertionCount; - - if (m_root == b2_nullNode) - { - m_root = leaf; - m_nodes[m_root].parent = b2_nullNode; - return; - } - - // Find the best sibling for this node - b2AABB leafAABB = m_nodes[leaf].aabb; - int32 index = m_root; - while (m_nodes[index].IsLeaf() == false) - { - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - float32 area = m_nodes[index].aabb.GetPerimeter(); - - b2AABB combinedAABB; - combinedAABB.Combine(m_nodes[index].aabb, leafAABB); - float32 combinedArea = combinedAABB.GetPerimeter(); - - // Cost of creating a new parent for this node and the new leaf - float32 cost = 2.0f * combinedArea; - - // Minimum cost of pushing the leaf further down the tree - float32 inheritanceCost = 2.0f * (combinedArea - area); - - // Cost of descending into child1 - float32 cost1; - if (m_nodes[child1].IsLeaf()) - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child1].aabb); - cost1 = aabb.GetPerimeter() + inheritanceCost; - } - else - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child1].aabb); - float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); - float32 newArea = aabb.GetPerimeter(); - cost1 = (newArea - oldArea) + inheritanceCost; - } - - // Cost of descending into child2 - float32 cost2; - if (m_nodes[child2].IsLeaf()) - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child2].aabb); - cost2 = aabb.GetPerimeter() + inheritanceCost; - } - else - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child2].aabb); - float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); - float32 newArea = aabb.GetPerimeter(); - cost2 = newArea - oldArea + inheritanceCost; - } - - // Descend according to the minimum cost. - if (cost < cost1 && cost < cost2) - { - break; - } - - // Descend - if (cost1 < cost2) - { - index = child1; - } - else - { - index = child2; - } - } - - int32 sibling = index; - - // Create a new parent. - int32 oldParent = m_nodes[sibling].parent; - int32 newParent = AllocateNode(); - m_nodes[newParent].parent = oldParent; - m_nodes[newParent].userData = NULL; - m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); - m_nodes[newParent].height = m_nodes[sibling].height + 1; - - if (oldParent != b2_nullNode) - { - // The sibling was not the root. - if (m_nodes[oldParent].child1 == sibling) - { - m_nodes[oldParent].child1 = newParent; - } - else - { - m_nodes[oldParent].child2 = newParent; - } - - m_nodes[newParent].child1 = sibling; - m_nodes[newParent].child2 = leaf; - m_nodes[sibling].parent = newParent; - m_nodes[leaf].parent = newParent; - } - else - { - // The sibling was the root. - m_nodes[newParent].child1 = sibling; - m_nodes[newParent].child2 = leaf; - m_nodes[sibling].parent = newParent; - m_nodes[leaf].parent = newParent; - m_root = newParent; - } - - // Walk back up the tree fixing heights and AABBs - index = m_nodes[leaf].parent; - while (index != b2_nullNode) - { - index = Balance(index); - - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - b2Assert(child1 != b2_nullNode); - b2Assert(child2 != b2_nullNode); - - m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); - m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - - index = m_nodes[index].parent; - } - - //Validate(); -} - -void b2DynamicTree::RemoveLeaf(int32 leaf) -{ - if (leaf == m_root) - { - m_root = b2_nullNode; - return; - } - - int32 parent = m_nodes[leaf].parent; - int32 grandParent = m_nodes[parent].parent; - int32 sibling; - if (m_nodes[parent].child1 == leaf) - { - sibling = m_nodes[parent].child2; - } - else - { - sibling = m_nodes[parent].child1; - } - - if (grandParent != b2_nullNode) - { - // Destroy parent and connect sibling to grandParent. - if (m_nodes[grandParent].child1 == parent) - { - m_nodes[grandParent].child1 = sibling; - } - else - { - m_nodes[grandParent].child2 = sibling; - } - m_nodes[sibling].parent = grandParent; - FreeNode(parent); - - // Adjust ancestor bounds. - int32 index = grandParent; - while (index != b2_nullNode) - { - index = Balance(index); - - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); - - index = m_nodes[index].parent; - } - } - else - { - m_root = sibling; - m_nodes[sibling].parent = b2_nullNode; - FreeNode(parent); - } - - //Validate(); -} - -// Perform a left or right rotation if node A is imbalanced. -// Returns the new root index. -int32 b2DynamicTree::Balance(int32 iA) -{ - b2Assert(iA != b2_nullNode); - - b2TreeNode* A = m_nodes + iA; - if (A->IsLeaf() || A->height < 2) - { - return iA; - } - - int32 iB = A->child1; - int32 iC = A->child2; - b2Assert(0 <= iB && iB < m_nodeCapacity); - b2Assert(0 <= iC && iC < m_nodeCapacity); - - b2TreeNode* B = m_nodes + iB; - b2TreeNode* C = m_nodes + iC; - - int32 balance = C->height - B->height; - - // Rotate C up - if (balance > 1) - { - int32 iF = C->child1; - int32 iG = C->child2; - b2TreeNode* F = m_nodes + iF; - b2TreeNode* G = m_nodes + iG; - b2Assert(0 <= iF && iF < m_nodeCapacity); - b2Assert(0 <= iG && iG < m_nodeCapacity); - - // Swap A and C - C->child1 = iA; - C->parent = A->parent; - A->parent = iC; - - // A's old parent should point to C - if (C->parent != b2_nullNode) - { - if (m_nodes[C->parent].child1 == iA) - { - m_nodes[C->parent].child1 = iC; - } - else - { - b2Assert(m_nodes[C->parent].child2 == iA); - m_nodes[C->parent].child2 = iC; - } - } - else - { - m_root = iC; - } - - // Rotate - if (F->height > G->height) - { - C->child2 = iF; - A->child2 = iG; - G->parent = iA; - A->aabb.Combine(B->aabb, G->aabb); - C->aabb.Combine(A->aabb, F->aabb); - - A->height = 1 + b2Max(B->height, G->height); - C->height = 1 + b2Max(A->height, F->height); - } - else - { - C->child2 = iG; - A->child2 = iF; - F->parent = iA; - A->aabb.Combine(B->aabb, F->aabb); - C->aabb.Combine(A->aabb, G->aabb); - - A->height = 1 + b2Max(B->height, F->height); - C->height = 1 + b2Max(A->height, G->height); - } - - return iC; - } - - // Rotate B up - if (balance < -1) - { - int32 iD = B->child1; - int32 iE = B->child2; - b2TreeNode* D = m_nodes + iD; - b2TreeNode* E = m_nodes + iE; - b2Assert(0 <= iD && iD < m_nodeCapacity); - b2Assert(0 <= iE && iE < m_nodeCapacity); - - // Swap A and B - B->child1 = iA; - B->parent = A->parent; - A->parent = iB; - - // A's old parent should point to B - if (B->parent != b2_nullNode) - { - if (m_nodes[B->parent].child1 == iA) - { - m_nodes[B->parent].child1 = iB; - } - else - { - b2Assert(m_nodes[B->parent].child2 == iA); - m_nodes[B->parent].child2 = iB; - } - } - else - { - m_root = iB; - } - - // Rotate - if (D->height > E->height) - { - B->child2 = iD; - A->child1 = iE; - E->parent = iA; - A->aabb.Combine(C->aabb, E->aabb); - B->aabb.Combine(A->aabb, D->aabb); - - A->height = 1 + b2Max(C->height, E->height); - B->height = 1 + b2Max(A->height, D->height); - } - else - { - B->child2 = iE; - A->child1 = iD; - D->parent = iA; - A->aabb.Combine(C->aabb, D->aabb); - B->aabb.Combine(A->aabb, E->aabb); - - A->height = 1 + b2Max(C->height, D->height); - B->height = 1 + b2Max(A->height, E->height); - } - - return iB; - } - - return iA; -} - -int32 b2DynamicTree::GetHeight() const -{ - if (m_root == b2_nullNode) - { - return 0; - } - - return m_nodes[m_root].height; -} - -// -float32 b2DynamicTree::GetAreaRatio() const -{ - if (m_root == b2_nullNode) - { - return 0.0f; - } - - const b2TreeNode* root = m_nodes + m_root; - float32 rootArea = root->aabb.GetPerimeter(); - - float32 totalArea = 0.0f; - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - const b2TreeNode* node = m_nodes + i; - if (node->height < 0) - { - // Free node in pool - continue; - } - - totalArea += node->aabb.GetPerimeter(); - } - - return totalArea / rootArea; -} - -// Compute the height of a sub-tree. -int32 b2DynamicTree::ComputeHeight(int32 nodeId) const -{ - b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); - b2TreeNode* node = m_nodes + nodeId; - - if (node->IsLeaf()) - { - return 0; - } - - int32 height1 = ComputeHeight(node->child1); - int32 height2 = ComputeHeight(node->child2); - return 1 + b2Max(height1, height2); -} - -int32 b2DynamicTree::ComputeHeight() const -{ - int32 height = ComputeHeight(m_root); - return height; -} - -void b2DynamicTree::ValidateStructure(int32 index) const -{ - if (index == b2_nullNode) - { - return; - } - - if (index == m_root) - { - b2Assert(m_nodes[index].parent == b2_nullNode); - } - - const b2TreeNode* node = m_nodes + index; - - int32 child1 = node->child1; - int32 child2 = node->child2; - - if (node->IsLeaf()) - { - b2Assert(child1 == b2_nullNode); - b2Assert(child2 == b2_nullNode); - b2Assert(node->height == 0); - return; - } - - b2Assert(0 <= child1 && child1 < m_nodeCapacity); - b2Assert(0 <= child2 && child2 < m_nodeCapacity); - - b2Assert(m_nodes[child1].parent == index); - b2Assert(m_nodes[child2].parent == index); - - ValidateStructure(child1); - ValidateStructure(child2); -} - -void b2DynamicTree::ValidateMetrics(int32 index) const -{ - if (index == b2_nullNode) - { - return; - } - - const b2TreeNode* node = m_nodes + index; - - int32 child1 = node->child1; - int32 child2 = node->child2; - - if (node->IsLeaf()) - { - b2Assert(child1 == b2_nullNode); - b2Assert(child2 == b2_nullNode); - b2Assert(node->height == 0); - return; - } - - b2Assert(0 <= child1 && child1 < m_nodeCapacity); - b2Assert(0 <= child2 && child2 < m_nodeCapacity); - - int32 height1 = m_nodes[child1].height; - int32 height2 = m_nodes[child2].height; - int32 height; - height = 1 + b2Max(height1, height2); - b2Assert(node->height == height); - - b2AABB aabb; - aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - - b2Assert(aabb.lowerBound == node->aabb.lowerBound); - b2Assert(aabb.upperBound == node->aabb.upperBound); - - ValidateMetrics(child1); - ValidateMetrics(child2); -} - -void b2DynamicTree::Validate() const -{ - ValidateStructure(m_root); - ValidateMetrics(m_root); - - int32 freeCount = 0; - int32 freeIndex = m_freeList; - while (freeIndex != b2_nullNode) - { - b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); - freeIndex = m_nodes[freeIndex].next; - ++freeCount; - } - - b2Assert(GetHeight() == ComputeHeight()); - - b2Assert(m_nodeCount + freeCount == m_nodeCapacity); -} - -int32 b2DynamicTree::GetMaxBalance() const -{ - int32 maxBalance = 0; - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - const b2TreeNode* node = m_nodes + i; - if (node->height <= 1) - { - continue; - } - - b2Assert(node->IsLeaf() == false); - - int32 child1 = node->child1; - int32 child2 = node->child2; - int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); - maxBalance = b2Max(maxBalance, balance); - } - - return maxBalance; -} - -void b2DynamicTree::RebuildBottomUp() -{ - int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); - int32 count = 0; - - // Build array of leaves. Free the rest. - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - if (m_nodes[i].height < 0) - { - // free node in pool - continue; - } - - if (m_nodes[i].IsLeaf()) - { - m_nodes[i].parent = b2_nullNode; - nodes[count] = i; - ++count; - } - else - { - FreeNode(i); - } - } - - while (count > 1) - { - float32 minCost = b2_maxFloat; - int32 iMin = -1, jMin = -1; - for (int32 i = 0; i < count; ++i) - { - b2AABB aabbi = m_nodes[nodes[i]].aabb; - - for (int32 j = i + 1; j < count; ++j) - { - b2AABB aabbj = m_nodes[nodes[j]].aabb; - b2AABB b; - b.Combine(aabbi, aabbj); - float32 cost = b.GetPerimeter(); - if (cost < minCost) - { - iMin = i; - jMin = j; - minCost = cost; - } - } - } - - int32 index1 = nodes[iMin]; - int32 index2 = nodes[jMin]; - b2TreeNode* child1 = m_nodes + index1; - b2TreeNode* child2 = m_nodes + index2; - - int32 parentIndex = AllocateNode(); - b2TreeNode* parent = m_nodes + parentIndex; - parent->child1 = index1; - parent->child2 = index2; - parent->height = 1 + b2Max(child1->height, child2->height); - parent->aabb.Combine(child1->aabb, child2->aabb); - parent->parent = b2_nullNode; - - child1->parent = parentIndex; - child2->parent = parentIndex; - - nodes[jMin] = nodes[count-1]; - nodes[iMin] = parentIndex; - --count; - } - - m_root = nodes[0]; - b2Free(nodes); - - Validate(); -} diff --git a/external/Box2D/Collision/b2DynamicTree.h b/external/Box2D/Collision/b2DynamicTree.h deleted file mode 100644 index 33f16b0f32..0000000000 --- a/external/Box2D/Collision/b2DynamicTree.h +++ /dev/null @@ -1,284 +0,0 @@ -/* -* Copyright (c) 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. -*/ - -#ifndef B2_DYNAMIC_TREE_H -#define B2_DYNAMIC_TREE_H - -#include -#include - -#define b2_nullNode (-1) - -/// A node in the dynamic tree. The client does not interact with this directly. -struct b2TreeNode -{ - bool IsLeaf() const - { - return child1 == b2_nullNode; - } - - /// Enlarged AABB - b2AABB aabb; - - void* userData; - - union - { - int32 parent; - int32 next; - }; - - int32 child1; - int32 child2; - - // leaf = 0, free node = -1 - int32 height; -}; - -/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. -/// A dynamic tree arranges data in a binary tree to accelerate -/// queries such as volume queries and ray casts. Leafs are proxies -/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor -/// so that the proxy AABB is bigger than the client object. This allows the client -/// object to move by small amounts without triggering a tree update. -/// -/// Nodes are pooled and relocatable, so we use node indices rather than pointers. -class b2DynamicTree -{ -public: - /// Constructing the tree initializes the node pool. - b2DynamicTree(); - - /// Destroy the tree, freeing the node pool. - ~b2DynamicTree(); - - /// Create a proxy. Provide a tight fitting AABB and a userData pointer. - int32 CreateProxy(const b2AABB& aabb, void* userData); - - /// Destroy a proxy. This asserts if the id is invalid. - void DestroyProxy(int32 proxyId); - - /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, - /// then the proxy is removed from the tree and re-inserted. Otherwise - /// the function returns immediately. - /// @return true if the proxy was re-inserted. - bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); - - /// Get proxy user data. - /// @return the proxy user data or 0 if the id is invalid. - void* GetUserData(int32 proxyId) const; - - /// Get the fat AABB for a proxy. - const b2AABB& GetFatAABB(int32 proxyId) const; - - /// Query an AABB for overlapping proxies. The callback class - /// is called for each proxy that overlaps the supplied AABB. - template - void Query(T* callback, const b2AABB& aabb) const; - - /// Ray-cast against the proxies in the tree. This relies on the callback - /// to perform a exact ray-cast in the case were the proxy contains a shape. - /// The callback also performs the any collision filtering. This has performance - /// roughly equal to k * log(n), where k is the number of collisions and n is the - /// number of proxies in the tree. - /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). - /// @param callback a callback class that is called for each proxy that is hit by the ray. - template - void RayCast(T* callback, const b2RayCastInput& input) const; - - /// Validate this tree. For testing. - void Validate() const; - - /// Compute the height of the binary tree in O(N) time. Should not be - /// called often. - int32 GetHeight() const; - - /// Get the maximum balance of an node in the tree. The balance is the difference - /// in height of the two children of a node. - int32 GetMaxBalance() const; - - /// Get the ratio of the sum of the node areas to the root area. - float32 GetAreaRatio() const; - - /// Build an optimal tree. Very expensive. For testing. - void RebuildBottomUp(); - -private: - - int32 AllocateNode(); - void FreeNode(int32 node); - - void InsertLeaf(int32 node); - void RemoveLeaf(int32 node); - - int32 Balance(int32 index); - - int32 ComputeHeight() const; - int32 ComputeHeight(int32 nodeId) const; - - void ValidateStructure(int32 index) const; - void ValidateMetrics(int32 index) const; - - int32 m_root; - - b2TreeNode* m_nodes; - int32 m_nodeCount; - int32 m_nodeCapacity; - - int32 m_freeList; - - /// This is used to incrementally traverse the tree for re-balancing. - uint32 m_path; - - int32 m_insertionCount; -}; - -inline void* b2DynamicTree::GetUserData(int32 proxyId) const -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - return m_nodes[proxyId].userData; -} - -inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - return m_nodes[proxyId].aabb; -} - -template -inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const -{ - b2GrowableStack stack; - stack.Push(m_root); - - while (stack.GetCount() > 0) - { - int32 nodeId = stack.Pop(); - if (nodeId == b2_nullNode) - { - continue; - } - - const b2TreeNode* node = m_nodes + nodeId; - - if (b2TestOverlap(node->aabb, aabb)) - { - if (node->IsLeaf()) - { - bool proceed = callback->QueryCallback(nodeId); - if (proceed == false) - { - return; - } - } - else - { - stack.Push(node->child1); - stack.Push(node->child2); - } - } - } -} - -template -inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const -{ - b2Vec2 p1 = input.p1; - b2Vec2 p2 = input.p2; - b2Vec2 r = p2 - p1; - b2Assert(r.LengthSquared() > 0.0f); - r.Normalize(); - - // v is perpendicular to the segment. - b2Vec2 v = b2Cross(1.0f, r); - b2Vec2 abs_v = b2Abs(v); - - // Separating axis for segment (Gino, p80). - // |dot(v, p1 - c)| > dot(|v|, h) - - float32 maxFraction = input.maxFraction; - - // Build a bounding box for the segment. - b2AABB segmentAABB; - { - b2Vec2 t = p1 + maxFraction * (p2 - p1); - segmentAABB.lowerBound = b2Min(p1, t); - segmentAABB.upperBound = b2Max(p1, t); - } - - b2GrowableStack stack; - stack.Push(m_root); - - while (stack.GetCount() > 0) - { - int32 nodeId = stack.Pop(); - if (nodeId == b2_nullNode) - { - continue; - } - - const b2TreeNode* node = m_nodes + nodeId; - - if (b2TestOverlap(node->aabb, segmentAABB) == false) - { - continue; - } - - // Separating axis for segment (Gino, p80). - // |dot(v, p1 - c)| > dot(|v|, h) - b2Vec2 c = node->aabb.GetCenter(); - b2Vec2 h = node->aabb.GetExtents(); - float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); - if (separation > 0.0f) - { - continue; - } - - if (node->IsLeaf()) - { - b2RayCastInput subInput; - subInput.p1 = input.p1; - subInput.p2 = input.p2; - subInput.maxFraction = maxFraction; - - float32 value = callback->RayCastCallback(subInput, nodeId); - - if (value == 0.0f) - { - // The client has terminated the ray cast. - return; - } - - if (value > 0.0f) - { - // Update segment bounding box. - maxFraction = value; - b2Vec2 t = p1 + maxFraction * (p2 - p1); - segmentAABB.lowerBound = b2Min(p1, t); - segmentAABB.upperBound = b2Max(p1, t); - } - } - else - { - stack.Push(node->child1); - stack.Push(node->child2); - } - } -} - -#endif diff --git a/external/Box2D/Collision/b2TimeOfImpact.cpp b/external/Box2D/Collision/b2TimeOfImpact.cpp deleted file mode 100644 index 1d643addd8..0000000000 --- a/external/Box2D/Collision/b2TimeOfImpact.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include -#include -#include - -#ifdef SHP -#include -#else -#include -#endif - -using namespace std; - -int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; -int32 b2_toiRootIters, b2_toiMaxRootIters; - -struct b2SeparationFunction -{ - enum Type - { - e_points, - e_faceA, - e_faceB - }; - - // TODO_ERIN might not need to return the separation - - float32 Initialize(const b2SimplexCache* cache, - const b2DistanceProxy* proxyA, const b2Sweep& sweepA, - const b2DistanceProxy* proxyB, const b2Sweep& sweepB, - float32 t1) - { - m_proxyA = proxyA; - m_proxyB = proxyB; - int32 count = cache->count; - b2Assert(0 < count && count < 3); - - m_sweepA = sweepA; - m_sweepB = sweepB; - - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t1); - m_sweepB.GetTransform(&xfB, t1); - - if (count == 1) - { - m_type = e_points; - b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); - b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - m_axis = pointB - pointA; - float32 s = m_axis.Normalize(); - return s; - } - else if (cache->indexA[0] == cache->indexA[1]) - { - // Two points on B and one on A. - m_type = e_faceB; - b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); - b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); - - m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); - m_axis.Normalize(); - b2Vec2 normal = b2Mul(xfB.q, m_axis); - - m_localPoint = 0.5f * (localPointB1 + localPointB2); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 s = b2Dot(pointA - pointB, normal); - if (s < 0.0f) - { - m_axis = -m_axis; - s = -s; - } - return s; - } - else - { - // Two points on A and one or two points on B. - m_type = e_faceA; - b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); - b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); - - m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); - m_axis.Normalize(); - b2Vec2 normal = b2Mul(xfA.q, m_axis); - - m_localPoint = 0.5f * (localPointA1 + localPointA2); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 s = b2Dot(pointB - pointA, normal); - if (s < 0.0f) - { - m_axis = -m_axis; - s = -s; - } - return s; - } - } - - float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const - { - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t); - m_sweepB.GetTransform(&xfB, t); - - switch (m_type) - { - case e_points: - { - b2Vec2 axisA = b2MulT(xfA.q, m_axis); - b2Vec2 axisB = b2MulT(xfB.q, -m_axis); - - *indexA = m_proxyA->GetSupport(axisA); - *indexB = m_proxyB->GetSupport(axisB); - - b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); - b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); - - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, m_axis); - return separation; - } - - case e_faceA: - { - b2Vec2 normal = b2Mul(xfA.q, m_axis); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 axisB = b2MulT(xfB.q, -normal); - - *indexA = -1; - *indexB = m_proxyB->GetSupport(axisB); - - b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, normal); - return separation; - } - - case e_faceB: - { - b2Vec2 normal = b2Mul(xfB.q, m_axis); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 axisA = b2MulT(xfA.q, -normal); - - *indexB = -1; - *indexA = m_proxyA->GetSupport(axisA); - - b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 separation = b2Dot(pointA - pointB, normal); - return separation; - } - - default: - b2Assert(false); - *indexA = -1; - *indexB = -1; - return 0.0f; - } - } - - float32 Evaluate(int32 indexA, int32 indexB, float32 t) const - { - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t); - m_sweepB.GetTransform(&xfB, t); - - switch (m_type) - { - case e_points: - { - b2Vec2 axisA = b2MulT(xfA.q, m_axis); - b2Vec2 axisB = b2MulT(xfB.q, -m_axis); - - b2Vec2 localPointA = m_proxyA->GetVertex(indexA); - b2Vec2 localPointB = m_proxyB->GetVertex(indexB); - - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - float32 separation = b2Dot(pointB - pointA, m_axis); - - return separation; - } - - case e_faceA: - { - b2Vec2 normal = b2Mul(xfA.q, m_axis); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 axisB = b2MulT(xfB.q, -normal); - - b2Vec2 localPointB = m_proxyB->GetVertex(indexB); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, normal); - return separation; - } - - case e_faceB: - { - b2Vec2 normal = b2Mul(xfB.q, m_axis); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 axisA = b2MulT(xfA.q, -normal); - - b2Vec2 localPointA = m_proxyA->GetVertex(indexA); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 separation = b2Dot(pointA - pointB, normal); - return separation; - } - - default: - b2Assert(false); - return 0.0f; - } - } - - const b2DistanceProxy* m_proxyA; - const b2DistanceProxy* m_proxyB; - b2Sweep m_sweepA, m_sweepB; - Type m_type; - b2Vec2 m_localPoint; - b2Vec2 m_axis; -}; - -// CCD via the local separating axis method. This seeks progression -// by computing the largest time at which separation is maintained. -void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) -{ - ++b2_toiCalls; - - output->state = b2TOIOutput::e_unknown; - output->t = input->tMax; - - const b2DistanceProxy* proxyA = &input->proxyA; - const b2DistanceProxy* proxyB = &input->proxyB; - - b2Sweep sweepA = input->sweepA; - b2Sweep sweepB = input->sweepB; - - // Large rotations can make the root finder fail, so we normalize the - // sweep angles. - sweepA.Normalize(); - sweepB.Normalize(); - - float32 tMax = input->tMax; - - float32 totalRadius = proxyA->m_radius + proxyB->m_radius; - float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); - float32 tolerance = 0.25f * b2_linearSlop; - b2Assert(target > tolerance); - - float32 t1 = 0.0f; - const int32 k_maxIterations = 20; // TODO_ERIN b2Settings - int32 iter = 0; - - // Prepare input for distance query. - b2SimplexCache cache; - cache.count = 0; - b2DistanceInput distanceInput; - distanceInput.proxyA = input->proxyA; - distanceInput.proxyB = input->proxyB; - distanceInput.useRadii = false; - - // The outer loop progressively attempts to compute new separating axes. - // This loop terminates when an axis is repeated (no progress is made). - for(;;) - { - b2Transform xfA, xfB; - sweepA.GetTransform(&xfA, t1); - sweepB.GetTransform(&xfB, t1); - - // Get the distance between shapes. We can also use the results - // to get a separating axis. - distanceInput.transformA = xfA; - distanceInput.transformB = xfB; - b2DistanceOutput distanceOutput; - b2Distance(&distanceOutput, &cache, &distanceInput); - - // If the shapes are overlapped, we give up on continuous collision. - if (distanceOutput.distance <= 0.0f) - { - // Failure! - output->state = b2TOIOutput::e_overlapped; - output->t = 0.0f; - break; - } - - if (distanceOutput.distance < target + tolerance) - { - // Victory! - output->state = b2TOIOutput::e_touching; - output->t = t1; - break; - } - - // Initialize the separating axis. - b2SeparationFunction fcn; - fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); -#if 0 - // Dump the curve seen by the root finder - { - const int32 N = 100; - float32 dx = 1.0f / N; - float32 xs[N+1]; - float32 fs[N+1]; - - float32 x = 0.0f; - - for (int32 i = 0; i <= N; ++i) - { - sweepA.GetTransform(&xfA, x); - sweepB.GetTransform(&xfB, x); - float32 f = fcn.Evaluate(xfA, xfB) - target; - - printf("%g %g\n", x, f); - - xs[i] = x; - fs[i] = f; - - x += dx; - } - } -#endif - - // Compute the TOI on the separating axis. We do this by successively - // resolving the deepest point. This loop is bounded by the number of vertices. - bool done = false; - float32 t2 = tMax; - int32 pushBackIter = 0; - for (;;) - { - // Find the deepest point at t2. Store the witness point indices. - int32 indexA, indexB; - float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); - - // Is the final configuration separated? - if (s2 > target + tolerance) - { - // Victory! - output->state = b2TOIOutput::e_separated; - output->t = tMax; - done = true; - break; - } - - // Has the separation reached tolerance? - if (s2 > target - tolerance) - { - // Advance the sweeps - t1 = t2; - break; - } - - // Compute the initial separation of the witness points. - float32 s1 = fcn.Evaluate(indexA, indexB, t1); - - // Check for initial overlap. This might happen if the root finder - // runs out of iterations. - if (s1 < target - tolerance) - { - output->state = b2TOIOutput::e_failed; - output->t = t1; - done = true; - break; - } - - // Check for touching - if (s1 <= target + tolerance) - { - // Victory! t1 should hold the TOI (could be 0.0). - output->state = b2TOIOutput::e_touching; - output->t = t1; - done = true; - break; - } - - // Compute 1D root of: f(x) - target = 0 - int32 rootIterCount = 0; - float32 a1 = t1, a2 = t2; - for (;;) - { - // Use a mix of the secant rule and bisection. - float32 t; - if (rootIterCount & 1) - { - // Secant rule to improve convergence. - t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); - } - else - { - // Bisection to guarantee progress. - t = 0.5f * (a1 + a2); - } - - float32 s = fcn.Evaluate(indexA, indexB, t); - - if (b2Abs(s - target) < tolerance) - { - // t2 holds a tentative value for t1 - t2 = t; - break; - } - - // Ensure we continue to bracket the root. - if (s > target) - { - a1 = t; - s1 = s; - } - else - { - a2 = t; - s2 = s; - } - - ++rootIterCount; - ++b2_toiRootIters; - - if (rootIterCount == 50) - { - break; - } - } - - b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); - - ++pushBackIter; - - if (pushBackIter == b2_maxPolygonVertices) - { - break; - } - } - - ++iter; - ++b2_toiIters; - - if (done) - { - break; - } - - if (iter == k_maxIterations) - { - // Root finder got stuck. Semi-victory. - output->state = b2TOIOutput::e_failed; - output->t = t1; - break; - } - } - - b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); -} diff --git a/external/Box2D/Collision/b2TimeOfImpact.h b/external/Box2D/Collision/b2TimeOfImpact.h deleted file mode 100644 index 2e4f8228ff..0000000000 --- a/external/Box2D/Collision/b2TimeOfImpact.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_TIME_OF_IMPACT_H -#define B2_TIME_OF_IMPACT_H - -#include -#include - -/// Input parameters for b2TimeOfImpact -struct b2TOIInput -{ - b2DistanceProxy proxyA; - b2DistanceProxy proxyB; - b2Sweep sweepA; - b2Sweep sweepB; - float32 tMax; // defines sweep interval [0, tMax] -}; - -// Output parameters for b2TimeOfImpact. -struct b2TOIOutput -{ - enum State - { - e_unknown, - e_failed, - e_overlapped, - e_touching, - e_separated - }; - - State state; - float32 t; -}; - -/// Compute the upper bound on time before two shapes penetrate. Time is represented as -/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, -/// non-tunneling collision. If you change the time interval, you should call this function -/// again. -/// Note: use b2Distance to compute the contact point and normal at the time of impact. -void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); - -#endif diff --git a/external/Box2D/Common/b2BlockAllocator.cpp b/external/Box2D/Common/b2BlockAllocator.cpp deleted file mode 100644 index 2e862091f9..0000000000 --- a/external/Box2D/Common/b2BlockAllocator.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include - -using namespace std; - -int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = -{ - 16, // 0 - 32, // 1 - 64, // 2 - 96, // 3 - 128, // 4 - 160, // 5 - 192, // 6 - 224, // 7 - 256, // 8 - 320, // 9 - 384, // 10 - 448, // 11 - 512, // 12 - 640, // 13 -}; -uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; -bool b2BlockAllocator::s_blockSizeLookupInitialized; - -struct b2Chunk -{ - int32 blockSize; - b2Block* blocks; -}; - -struct b2Block -{ - b2Block* next; -}; - -b2BlockAllocator::b2BlockAllocator() -{ - b2Assert(b2_blockSizes < UCHAR_MAX); - - m_chunkSpace = b2_chunkArrayIncrement; - m_chunkCount = 0; - m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); - - memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); - memset(m_freeLists, 0, sizeof(m_freeLists)); - - if (s_blockSizeLookupInitialized == false) - { - int32 j = 0; - for (int32 i = 1; i <= b2_maxBlockSize; ++i) - { - b2Assert(j < b2_blockSizes); - if (i <= s_blockSizes[j]) - { - s_blockSizeLookup[i] = (uint8)j; - } - else - { - ++j; - s_blockSizeLookup[i] = (uint8)j; - } - } - - s_blockSizeLookupInitialized = true; - } -} - -b2BlockAllocator::~b2BlockAllocator() -{ - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Free(m_chunks[i].blocks); - } - - b2Free(m_chunks); -} - -void* b2BlockAllocator::Allocate(int32 size) -{ - if (size == 0) - return NULL; - - b2Assert(0 < size); - - if (size > b2_maxBlockSize) - { - return b2Alloc(size); - } - - int32 index = s_blockSizeLookup[size]; - b2Assert(0 <= index && index < b2_blockSizes); - - if (m_freeLists[index]) - { - b2Block* block = m_freeLists[index]; - m_freeLists[index] = block->next; - return block; - } - else - { - if (m_chunkCount == m_chunkSpace) - { - b2Chunk* oldChunks = m_chunks; - m_chunkSpace += b2_chunkArrayIncrement; - m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); - memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); - memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); - b2Free(oldChunks); - } - - b2Chunk* chunk = m_chunks + m_chunkCount; - chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); -#if defined(_DEBUG) - memset(chunk->blocks, 0xcd, b2_chunkSize); -#endif - int32 blockSize = s_blockSizes[index]; - chunk->blockSize = blockSize; - int32 blockCount = b2_chunkSize / blockSize; - b2Assert(blockCount * blockSize <= b2_chunkSize); - for (int32 i = 0; i < blockCount - 1; ++i) - { - b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); - b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); - block->next = next; - } - b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); - last->next = NULL; - - m_freeLists[index] = chunk->blocks->next; - ++m_chunkCount; - - return chunk->blocks; - } -} - -void b2BlockAllocator::Free(void* p, int32 size) -{ - if (size == 0) - { - return; - } - - b2Assert(0 < size); - - if (size > b2_maxBlockSize) - { - b2Free(p); - return; - } - - int32 index = s_blockSizeLookup[size]; - b2Assert(0 <= index && index < b2_blockSizes); - -#ifdef _DEBUG - // Verify the memory address and size is valid. - int32 blockSize = s_blockSizes[index]; - bool found = false; - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Chunk* chunk = m_chunks + i; - if (chunk->blockSize != blockSize) - { - b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || - (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); - } - else - { - if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) - { - found = true; - } - } - } - - b2Assert(found); - - memset(p, 0xfd, blockSize); -#endif - - b2Block* block = (b2Block*)p; - block->next = m_freeLists[index]; - m_freeLists[index] = block; -} - -void b2BlockAllocator::Clear() -{ - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Free(m_chunks[i].blocks); - } - - m_chunkCount = 0; - memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); - - memset(m_freeLists, 0, sizeof(m_freeLists)); -} diff --git a/external/Box2D/Common/b2BlockAllocator.h b/external/Box2D/Common/b2BlockAllocator.h deleted file mode 100644 index ec221fdf61..0000000000 --- a/external/Box2D/Common/b2BlockAllocator.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_BLOCK_ALLOCATOR_H -#define B2_BLOCK_ALLOCATOR_H - -#include - -const int32 b2_chunkSize = 16 * 1024; -const int32 b2_maxBlockSize = 640; -const int32 b2_blockSizes = 14; -const int32 b2_chunkArrayIncrement = 128; - -struct b2Block; -struct b2Chunk; - -/// This is a small object allocator used for allocating small -/// objects that persist for more than one time step. -/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp -class b2BlockAllocator -{ -public: - b2BlockAllocator(); - ~b2BlockAllocator(); - - /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. - void* Allocate(int32 size); - - /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. - void Free(void* p, int32 size); - - void Clear(); - -private: - - b2Chunk* m_chunks; - int32 m_chunkCount; - int32 m_chunkSpace; - - b2Block* m_freeLists[b2_blockSizes]; - - static int32 s_blockSizes[b2_blockSizes]; - static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; - static bool s_blockSizeLookupInitialized; -}; - -#endif diff --git a/external/Box2D/Common/b2Draw.cpp b/external/Box2D/Common/b2Draw.cpp deleted file mode 100644 index cb760025e9..0000000000 --- a/external/Box2D/Common/b2Draw.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -b2Draw::b2Draw() -{ - m_drawFlags = 0; -} - -void b2Draw::SetFlags(uint32 flags) -{ - m_drawFlags = flags; -} - -uint32 b2Draw::GetFlags() const -{ - return m_drawFlags; -} - -void b2Draw::AppendFlags(uint32 flags) -{ - m_drawFlags |= flags; -} - -void b2Draw::ClearFlags(uint32 flags) -{ - m_drawFlags &= ~flags; -} diff --git a/external/Box2D/Common/b2Draw.h b/external/Box2D/Common/b2Draw.h deleted file mode 100644 index b33cd8d38f..0000000000 --- a/external/Box2D/Common/b2Draw.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -/// Color for debug drawing. Each value has the range [0,1]. -struct b2Color -{ - b2Color() {} - b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} - void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } - float32 r, g, b; -}; - -/// Implement and register this class with a b2World to provide debug drawing of physics -/// entities in your game. -class b2Draw -{ -public: - b2Draw(); - - virtual ~b2Draw() {} - - enum - { - e_shapeBit = 0x0001, ///< draw shapes - e_jointBit = 0x0002, ///< draw joint connections - e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes - e_pairBit = 0x0008, ///< draw broad-phase pairs - e_centerOfMassBit = 0x0010 ///< draw center of mass frame - }; - - /// Set the drawing flags. - void SetFlags(uint32 flags); - - /// Get the drawing flags. - uint32 GetFlags() const; - - /// Append flags to the current flags. - void AppendFlags(uint32 flags); - - /// Clear flags from the current flags. - void ClearFlags(uint32 flags); - - /// Draw a closed polygon provided in CCW order. - virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; - - /// Draw a solid closed polygon provided in CCW order. - virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; - - /// Draw a circle. - virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; - - /// Draw a solid circle. - virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; - - /// Draw a line segment. - virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; - - /// Draw a transform. Choose your own length scale. - /// @param xf a transform. - virtual void DrawTransform(const b2Transform& xf) = 0; - -protected: - uint32 m_drawFlags; -}; diff --git a/external/Box2D/Common/b2GrowableStack.h b/external/Box2D/Common/b2GrowableStack.h deleted file mode 100644 index 68809521f4..0000000000 --- a/external/Box2D/Common/b2GrowableStack.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -* Copyright (c) 2010 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. -*/ - -#ifndef B2_GROWABLE_STACK_H -#define B2_GROWABLE_STACK_H -#include -#include - -/// This is a growable LIFO stack with an initial capacity of N. -/// If the stack size exceeds the initial capacity, the heap is used -/// to increase the size of the stack. -template -class b2GrowableStack -{ -public: - b2GrowableStack() - { - m_stack = m_array; - m_count = 0; - m_capacity = N; - } - - ~b2GrowableStack() - { - if (m_stack != m_array) - { - b2Free(m_stack); - m_stack = NULL; - } - } - - void Push(const T& element) - { - if (m_count == m_capacity) - { - T* old = m_stack; - m_capacity *= 2; - m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); - std::memcpy(m_stack, old, m_count * sizeof(T)); - if (old != m_array) - { - b2Free(old); - } - } - - m_stack[m_count] = element; - ++m_count; - } - - T Pop() - { - b2Assert(m_count > 0); - --m_count; - return m_stack[m_count]; - } - - int32 GetCount() - { - return m_count; - } - -private: - T* m_stack; - T m_array[N]; - int32 m_count; - int32 m_capacity; -}; - - -#endif diff --git a/external/Box2D/Common/b2Math.cpp b/external/Box2D/Common/b2Math.cpp deleted file mode 100644 index 15d68fce96..0000000000 --- a/external/Box2D/Common/b2Math.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include - -const b2Vec2 b2Vec2_zero(0.0f, 0.0f); - -/// Solve A * x = b, where b is a column vector. This is more efficient -/// than computing the inverse in one-shot cases. -b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const -{ - float32 det = b2Dot(ex, b2Cross(ey, ez)); - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec3 x; - x.x = det * b2Dot(b, b2Cross(ey, ez)); - x.y = det * b2Dot(ex, b2Cross(b, ez)); - x.z = det * b2Dot(ex, b2Cross(ey, b)); - return x; -} - -/// Solve A * x = b, where b is a column vector. This is more efficient -/// than computing the inverse in one-shot cases. -b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const -{ - float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; - float32 det = a11 * a22 - a12 * a21; - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec2 x; - x.x = det * (a22 * b.x - a12 * b.y); - x.y = det * (a11 * b.y - a21 * b.x); - return x; -} - -/// -void b2Mat33::GetInverse22(b2Mat33* M) const -{ - float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; - float32 det = a * d - b * c; - if (det != 0.0f) - { - det = 1.0f / det; - } - - M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; - M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; - M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; -} - -/// Returns the zero matrix if singular. -void b2Mat33::GetSymInverse33(b2Mat33* M) const -{ - float32 det = b2Dot(ex, b2Cross(ey, ez)); - if (det != 0.0f) - { - det = 1.0f / det; - } - - float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; - float32 a22 = ey.y, a23 = ez.y; - float32 a33 = ez.z; - - M->ex.x = det * (a22 * a33 - a23 * a23); - M->ex.y = det * (a13 * a23 - a12 * a33); - M->ex.z = det * (a12 * a23 - a13 * a22); - - M->ey.x = M->ex.y; - M->ey.y = det * (a11 * a33 - a13 * a13); - M->ey.z = det * (a13 * a12 - a11 * a23); - - M->ez.x = M->ex.z; - M->ez.y = M->ey.z; - M->ez.z = det * (a11 * a22 - a12 * a12); -} diff --git a/external/Box2D/Common/b2Math.h b/external/Box2D/Common/b2Math.h deleted file mode 100644 index a6be671139..0000000000 --- a/external/Box2D/Common/b2Math.h +++ /dev/null @@ -1,738 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_MATH_H -#define B2_MATH_H - -#include - -#include -#ifndef SHP -#include -#else -#include -#endif -#include -#include - -using namespace std; - - -/// This function is used to ensure that a floating point number is -/// not a NaN or infinity. -inline bool b2IsValid(float32 x) -{ - if (x != x) - { - // NaN. - return false; - } - - float32 infinity = std::numeric_limits::infinity(); - return -infinity < x && x < infinity; -} - -/// This is a approximate yet fast inverse square-root. -inline float32 b2InvSqrt(float32 x) -{ - union - { - float32 x; - int32 i; - } convert; - - convert.x = x; - float32 xhalf = 0.5f * x; - convert.i = 0x5f3759df - (convert.i >> 1); - x = convert.x; - x = x * (1.5f - xhalf * x * x); - return x; -} - -#define b2Sqrt(x) std::sqrt(x) -#define b2Atan2(y, x) std::atan2(y, x) - -/// A 2D column vector. -struct b2Vec2 -{ - /// Default constructor does nothing (for performance). - b2Vec2() {} - - /// Construct using coordinates. - b2Vec2(float32 x, float32 y) : x(x), y(y) {} - - /// Set this vector to all zeros. - void SetZero() { x = 0.0f; y = 0.0f; } - - /// Set this vector to some specified coordinates. - void Set(float32 x_, float32 y_) { x = x_; y = y_; } - - /// Negate this vector. - b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } - - /// Read from and indexed element. - float32 operator () (int32 i) const - { - return (&x)[i]; - } - - /// Write to an indexed element. - float32& operator () (int32 i) - { - return (&x)[i]; - } - - /// Add a vector to this vector. - void operator += (const b2Vec2& v) - { - x += v.x; y += v.y; - } - - /// Subtract a vector from this vector. - void operator -= (const b2Vec2& v) - { - x -= v.x; y -= v.y; - } - - /// Multiply this vector by a scalar. - void operator *= (float32 a) - { - x *= a; y *= a; - } - - /// Get the length of this vector (the norm). - float32 Length() const - { - return b2Sqrt(x * x + y * y); - } - - /// Get the length squared. For performance, use this instead of - /// b2Vec2::Length (if possible). - float32 LengthSquared() const - { - return x * x + y * y; - } - - /// Convert this vector into a unit vector. Returns the length. - float32 Normalize() - { - float32 length = Length(); - if (length < b2_epsilon) - { - return 0.0f; - } - float32 invLength = 1.0f / length; - x *= invLength; - y *= invLength; - - return length; - } - - /// Does this vector contain finite coordinates? - bool IsValid() const - { - return b2IsValid(x) && b2IsValid(y); - } - - /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) - b2Vec2 Skew() const - { - return b2Vec2(-y, x); - } - - float32 x, y; -}; - -/// A 2D column vector with 3 elements. -struct b2Vec3 -{ - /// Default constructor does nothing (for performance). - b2Vec3() {} - - /// Construct using coordinates. - b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} - - /// Set this vector to all zeros. - void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } - - /// Set this vector to some specified coordinates. - void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } - - /// Negate this vector. - b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } - - /// Add a vector to this vector. - void operator += (const b2Vec3& v) - { - x += v.x; y += v.y; z += v.z; - } - - /// Subtract a vector from this vector. - void operator -= (const b2Vec3& v) - { - x -= v.x; y -= v.y; z -= v.z; - } - - /// Multiply this vector by a scalar. - void operator *= (float32 s) - { - x *= s; y *= s; z *= s; - } - - float32 x, y, z; -}; - -/// A 2-by-2 matrix. Stored in column-major order. -struct b2Mat22 -{ - /// The default constructor does nothing (for performance). - b2Mat22() {} - - /// Construct this matrix using columns. - b2Mat22(const b2Vec2& c1, const b2Vec2& c2) - { - ex = c1; - ey = c2; - } - - /// Construct this matrix using scalars. - b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) - { - ex.x = a11; ex.y = a21; - ey.x = a12; ey.y = a22; - } - - /// Initialize this matrix using columns. - void Set(const b2Vec2& c1, const b2Vec2& c2) - { - ex = c1; - ey = c2; - } - - /// Set this to the identity matrix. - void SetIdentity() - { - ex.x = 1.0f; ey.x = 0.0f; - ex.y = 0.0f; ey.y = 1.0f; - } - - /// Set this matrix to all zeros. - void SetZero() - { - ex.x = 0.0f; ey.x = 0.0f; - ex.y = 0.0f; ey.y = 0.0f; - } - - b2Mat22 GetInverse() const - { - float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; - b2Mat22 B; - float32 det = a * d - b * c; - if (det != 0.0f) - { - det = 1.0f / det; - } - B.ex.x = det * d; B.ey.x = -det * b; - B.ex.y = -det * c; B.ey.y = det * a; - return B; - } - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. - b2Vec2 Solve(const b2Vec2& b) const - { - float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; - float32 det = a11 * a22 - a12 * a21; - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec2 x; - x.x = det * (a22 * b.x - a12 * b.y); - x.y = det * (a11 * b.y - a21 * b.x); - return x; - } - - b2Vec2 ex, ey; -}; - -/// A 3-by-3 matrix. Stored in column-major order. -struct b2Mat33 -{ - /// The default constructor does nothing (for performance). - b2Mat33() {} - - /// Construct this matrix using columns. - b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) - { - ex = c1; - ey = c2; - ez = c3; - } - - /// Set this matrix to all zeros. - void SetZero() - { - ex.SetZero(); - ey.SetZero(); - ez.SetZero(); - } - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. - b2Vec3 Solve33(const b2Vec3& b) const; - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. Solve only the upper - /// 2-by-2 matrix equation. - b2Vec2 Solve22(const b2Vec2& b) const; - - /// Get the inverse of this matrix as a 2-by-2. - /// Returns the zero matrix if singular. - void GetInverse22(b2Mat33* M) const; - - /// Get the symmetric inverse of this matrix as a 3-by-3. - /// Returns the zero matrix if singular. - void GetSymInverse33(b2Mat33* M) const; - - b2Vec3 ex, ey, ez; -}; - -/// Rotation -struct b2Rot -{ - b2Rot() {} - - /// Initialize from an angle in radians - explicit b2Rot(float32 angle) - { - /// TODO_ERIN optimize - s = sinf(angle); - c = cosf(angle); - } - - /// Set using an angle in radians. - void Set(float32 angle) - { - /// TODO_ERIN optimize - s = sinf(angle); - c = cosf(angle); - } - - /// Set to the identity rotation - void SetIdentity() - { - s = 0.0f; - c = 1.0f; - } - - /// Get the angle in radians - float32 GetAngle() const - { - return b2Atan2(s, c); - } - - /// Get the x-axis - b2Vec2 GetXAxis() const - { - return b2Vec2(c, s); - } - - /// Get the u-axis - b2Vec2 GetYAxis() const - { - return b2Vec2(-s, c); - } - - /// Sine and cosine - float32 s, c; -}; - -/// A transform contains translation and rotation. It is used to represent -/// the position and orientation of rigid frames. -struct b2Transform -{ - /// The default constructor does nothing. - b2Transform() {} - - /// Initialize using a position vector and a rotation. - b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} - - /// Set this to the identity transform. - void SetIdentity() - { - p.SetZero(); - q.SetIdentity(); - } - - /// Set this based on the position and angle. - void Set(const b2Vec2& position, float32 angle) - { - p = position; - q.Set(angle); - } - - b2Vec2 p; - b2Rot q; -}; - -/// This describes the motion of a body/shape for TOI computation. -/// Shapes are defined with respect to the body origin, which may -/// no coincide with the center of mass. However, to support dynamics -/// we must interpolate the center of mass position. -struct b2Sweep -{ - /// Get the interpolated transform at a specific time. - /// @param beta is a factor in [0,1], where 0 indicates alpha0. - void GetTransform(b2Transform* xfb, float32 beta) const; - - /// Advance the sweep forward, yielding a new initial state. - /// @param alpha the new initial time. - void Advance(float32 alpha); - - /// Normalize the angles. - void Normalize(); - - b2Vec2 localCenter; ///< local center of mass position - b2Vec2 c0, c; ///< center world positions - float32 a0, a; ///< world angles - - /// Fraction of the current time step in the range [0,1] - /// c0 and a0 are the positions at alpha0. - float32 alpha0; -}; - -/// Useful constant -extern const b2Vec2 b2Vec2_zero; - -/// Perform the dot product on two vectors. -inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) -{ - return a.x * b.x + a.y * b.y; -} - -/// Perform the cross product on two vectors. In 2D this produces a scalar. -inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) -{ - return a.x * b.y - a.y * b.x; -} - -/// Perform the cross product on a vector and a scalar. In 2D this produces -/// a vector. -inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) -{ - return b2Vec2(s * a.y, -s * a.x); -} - -/// Perform the cross product on a scalar and a vector. In 2D this produces -/// a vector. -inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) -{ - return b2Vec2(-s * a.y, s * a.x); -} - -/// Multiply a matrix times a vector. If a rotation matrix is provided, -/// then this transforms the vector from one frame to another. -inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) -{ - return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); -} - -/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, -/// then this transforms the vector from one frame to another (inverse transform). -inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) -{ - return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); -} - -/// Add two vectors component-wise. -inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(a.x + b.x, a.y + b.y); -} - -/// Subtract two vectors component-wise. -inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(a.x - b.x, a.y - b.y); -} - -inline b2Vec2 operator * (float32 s, const b2Vec2& a) -{ - return b2Vec2(s * a.x, s * a.y); -} - -inline bool operator == (const b2Vec2& a, const b2Vec2& b) -{ - return a.x == b.x && a.y == b.y; -} - -inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) -{ - b2Vec2 c = a - b; - return c.Length(); -} - -inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) -{ - b2Vec2 c = a - b; - return b2Dot(c, c); -} - -inline b2Vec3 operator * (float32 s, const b2Vec3& a) -{ - return b2Vec3(s * a.x, s * a.y, s * a.z); -} - -/// Add two vectors component-wise. -inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); -} - -/// Subtract two vectors component-wise. -inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); -} - -/// Perform the dot product on two vectors. -inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) -{ - return a.x * b.x + a.y * b.y + a.z * b.z; -} - -/// Perform the cross product on two vectors. -inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); -} - -inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) -{ - return b2Mat22(A.ex + B.ex, A.ey + B.ey); -} - -// A * B -inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) -{ - return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); -} - -// A^T * B -inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) -{ - b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); - b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); - return b2Mat22(c1, c2); -} - -/// Multiply a matrix times a vector. -inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) -{ - return v.x * A.ex + v.y * A.ey + v.z * A.ez; -} - -/// Multiply a matrix times a vector. -inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) -{ - return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); -} - -/// Multiply two rotations: q * r -inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) -{ - // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] - // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] - // s = qs * rc + qc * rs - // c = qc * rc - qs * rs - b2Rot qr; - qr.s = q.s * r.c + q.c * r.s; - qr.c = q.c * r.c - q.s * r.s; - return qr; -} - -/// Transpose multiply two rotations: qT * r -inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) -{ - // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] - // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] - // s = qc * rs - qs * rc - // c = qc * rc + qs * rs - b2Rot qr; - qr.s = q.c * r.s - q.s * r.c; - qr.c = q.c * r.c + q.s * r.s; - return qr; -} - -/// Rotate a vector -inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) -{ - return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); -} - -/// Inverse rotate a vector -inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) -{ - return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); -} - -inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) -{ - float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; - float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; - - return b2Vec2(x, y); -} - -inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) -{ - float32 px = v.x - T.p.x; - float32 py = v.y - T.p.y; - float32 x = (T.q.c * px + T.q.s * py); - float32 y = (-T.q.s * px + T.q.c * py); - - return b2Vec2(x, y); -} - -// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p -// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p -inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) -{ - b2Transform C; - C.q = b2Mul(A.q, B.q); - C.p = b2Mul(A.q, B.p) + A.p; - return C; -} - -// v2 = A.q' * (B.q * v1 + B.p - A.p) -// = A.q' * B.q * v1 + A.q' * (B.p - A.p) -inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) -{ - b2Transform C; - C.q = b2MulT(A.q, B.q); - C.p = b2MulT(A.q, B.p - A.p); - return C; -} - -template -inline T b2Abs(T a) -{ - return a > T(0) ? a : -a; -} - -inline b2Vec2 b2Abs(const b2Vec2& a) -{ - return b2Vec2(b2Abs(a.x), b2Abs(a.y)); -} - -inline b2Mat22 b2Abs(const b2Mat22& A) -{ - return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); -} - -template -inline T b2Min(T a, T b) -{ - return a < b ? a : b; -} - -inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); -} - -template -inline T b2Max(T a, T b) -{ - return a > b ? a : b; -} - -inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); -} - -template -inline T b2Clamp(T a, T low, T high) -{ - return b2Max(low, b2Min(a, high)); -} - -inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) -{ - return b2Max(low, b2Min(a, high)); -} - -template inline void b2Swap(T& a, T& b) -{ - T tmp = a; - a = b; - b = tmp; -} - -/// "Next Largest Power of 2 -/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm -/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with -/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next -/// largest power of 2. For a 32-bit value:" -inline uint32 b2NextPowerOfTwo(uint32 x) -{ - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return x + 1; -} - -inline bool b2IsPowerOfTwo(uint32 x) -{ - bool result = x > 0 && (x & (x - 1)) == 0; - return result; -} - -inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const -{ - xf->p = (1.0f - beta) * c0 + beta * c; - float32 angle = (1.0f - beta) * a0 + beta * a; - xf->q.Set(angle); - - // Shift to origin - xf->p -= b2Mul(xf->q, localCenter); -} - -inline void b2Sweep::Advance(float32 alpha) -{ - b2Assert(alpha0 < 1.0f); - float32 beta = (alpha - alpha0) / (1.0f - alpha0); - c0 = (1.0f - beta) * c0 + beta * c; - a0 = (1.0f - beta) * a0 + beta * a; - alpha0 = alpha; -} - -/// Normalize an angle in radians to be between -pi and pi -inline void b2Sweep::Normalize() -{ - float32 twoPi = 2.0f * b2_pi; - float32 d = twoPi * floorf(a0 / twoPi); - a0 -= d; - a -= d; -} - -#endif diff --git a/external/Box2D/Common/b2Settings.cpp b/external/Box2D/Common/b2Settings.cpp deleted file mode 100644 index 84d6f1d0e4..0000000000 --- a/external/Box2D/Common/b2Settings.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Copyright (c) 2006-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 -#ifdef SHP -#include -#include -#include -#include -#else -#include -#include -#include -#endif - - -using namespace std; - - -b2Version b2_version = {2, 2, 1}; - -// Memory allocators. Modify these to use your own allocator. -void* b2Alloc(int32 size) -{ - return malloc(size); -} - -void b2Free(void* mem) -{ - free(mem); -} - -// You can modify this to use your logging facility. -void b2Log(const char* string, ...) -{ -#if defined(SHP) - #ifdef _DEBUG - __App_info(__PRETTY_FUNCTION__ , __LINE__, string); - #endif -#else - va_list args; - va_start(args, string); - vprintf(string, args); - va_end(args); -#endif -} diff --git a/external/Box2D/Common/b2Settings.h b/external/Box2D/Common/b2Settings.h deleted file mode 100644 index aaf4b12ccf..0000000000 --- a/external/Box2D/Common/b2Settings.h +++ /dev/null @@ -1,150 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_SETTINGS_H -#define B2_SETTINGS_H - -#include -#include - -#define B2_NOT_USED(x) ((void)(x)) -#define b2Assert(A) assert(A) - -typedef signed char int8; -typedef signed short int16; -typedef signed int int32; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef float float32; -typedef double float64; - -#define b2_maxFloat FLT_MAX -#define b2_epsilon FLT_EPSILON -#define b2_pi 3.14159265359f - -/// @file -/// Global tuning constants based on meters-kilograms-seconds (MKS) units. -/// - -// Collision - -/// The maximum number of contact points between two convex shapes. Do -/// not change this value. -#define b2_maxManifoldPoints 2 - -/// The maximum number of vertices on a convex polygon. You cannot increase -/// this too much because b2BlockAllocator has a maximum object size. -#define b2_maxPolygonVertices 8 - -/// This is used to fatten AABBs in the dynamic tree. This allows proxies -/// to move by a small amount without triggering a tree adjustment. -/// This is in meters. -#define b2_aabbExtension 0.1f - -/// This is used to fatten AABBs in the dynamic tree. This is used to predict -/// the future position based on the current displacement. -/// This is a dimensionless multiplier. -#define b2_aabbMultiplier 2.0f - -/// A small length used as a collision and constraint tolerance. Usually it is -/// chosen to be numerically significant, but visually insignificant. -#define b2_linearSlop 0.005f - -/// A small angle used as a collision and constraint tolerance. Usually it is -/// chosen to be numerically significant, but visually insignificant. -#define b2_angularSlop (2.0f / 180.0f * b2_pi) - -/// The radius of the polygon/edge shape skin. This should not be modified. Making -/// this smaller means polygons will have an insufficient buffer for continuous collision. -/// Making it larger may create artifacts for vertex collision. -#define b2_polygonRadius (2.0f * b2_linearSlop) - -/// Maximum number of sub-steps per contact in continuous physics simulation. -#define b2_maxSubSteps 8 - - -// Dynamics - -/// Maximum number of contacts to be handled to solve a TOI impact. -#define b2_maxTOIContacts 32 - -/// A velocity threshold for elastic collisions. Any collision with a relative linear -/// velocity below this threshold will be treated as inelastic. -#define b2_velocityThreshold 1.0f - -/// The maximum linear position correction used when solving constraints. This helps to -/// prevent overshoot. -#define b2_maxLinearCorrection 0.2f - -/// The maximum angular position correction used when solving constraints. This helps to -/// prevent overshoot. -#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) - -/// The maximum linear velocity of a body. This limit is very large and is used -/// to prevent numerical problems. You shouldn't need to adjust this. -#define b2_maxTranslation 2.0f -#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) - -/// The maximum angular velocity of a body. This limit is very large and is used -/// to prevent numerical problems. You shouldn't need to adjust this. -#define b2_maxRotation (0.5f * b2_pi) -#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) - -/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so -/// that overlap is removed in one time step. However using values close to 1 often lead -/// to overshoot. -#define b2_baumgarte 0.2f -#define b2_toiBaugarte 0.75f - - -// Sleep - -/// The time that a body must be still before it will go to sleep. -#define b2_timeToSleep 0.5f - -/// A body cannot sleep if its linear velocity is above this tolerance. -#define b2_linearSleepTolerance 0.01f - -/// A body cannot sleep if its angular velocity is above this tolerance. -#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) - -// Memory Allocation - -/// Implement this function to use your own memory allocator. -void* b2Alloc(int32 size); - -/// If you implement b2Alloc, you should also implement this function. -void b2Free(void* mem); - -/// Logging function. -void b2Log(const char* string, ...); - -/// Version numbering scheme. -/// See http://en.wikipedia.org/wiki/Software_versioning -struct b2Version -{ - int32 major; ///< significant changes - int32 minor; ///< incremental changes - int32 revision; ///< bug fixes -}; - -/// Current version. -extern b2Version b2_version; - -#endif diff --git a/external/Box2D/Common/b2StackAllocator.cpp b/external/Box2D/Common/b2StackAllocator.cpp deleted file mode 100644 index 3caa5d9127..0000000000 --- a/external/Box2D/Common/b2StackAllocator.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -b2StackAllocator::b2StackAllocator() -{ - m_index = 0; - m_allocation = 0; - m_maxAllocation = 0; - m_entryCount = 0; -} - -b2StackAllocator::~b2StackAllocator() -{ - b2Assert(m_index == 0); - b2Assert(m_entryCount == 0); -} - -void* b2StackAllocator::Allocate(int32 size) -{ - b2Assert(m_entryCount < b2_maxStackEntries); - - b2StackEntry* entry = m_entries + m_entryCount; - entry->size = size; - if (m_index + size > b2_stackSize) - { - entry->data = (char*)b2Alloc(size); - entry->usedMalloc = true; - } - else - { - entry->data = m_data + m_index; - entry->usedMalloc = false; - m_index += size; - } - - m_allocation += size; - m_maxAllocation = b2Max(m_maxAllocation, m_allocation); - ++m_entryCount; - - return entry->data; -} - -void b2StackAllocator::Free(void* p) -{ - b2Assert(m_entryCount > 0); - b2StackEntry* entry = m_entries + m_entryCount - 1; - b2Assert(p == entry->data); - if (entry->usedMalloc) - { - b2Free(p); - } - else - { - m_index -= entry->size; - } - m_allocation -= entry->size; - --m_entryCount; - - p = NULL; -} - -int32 b2StackAllocator::GetMaxAllocation() const -{ - return m_maxAllocation; -} diff --git a/external/Box2D/Common/b2StackAllocator.h b/external/Box2D/Common/b2StackAllocator.h deleted file mode 100644 index 6140d0d802..0000000000 --- a/external/Box2D/Common/b2StackAllocator.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_STACK_ALLOCATOR_H -#define B2_STACK_ALLOCATOR_H - -#include - -const int32 b2_stackSize = 100 * 1024; // 100k -const int32 b2_maxStackEntries = 32; - -struct b2StackEntry -{ - char* data; - int32 size; - bool usedMalloc; -}; - -// This is a stack allocator used for fast per step allocations. -// You must nest allocate/free pairs. The code will assert -// if you try to interleave multiple allocate/free pairs. -class b2StackAllocator -{ -public: - b2StackAllocator(); - ~b2StackAllocator(); - - void* Allocate(int32 size); - void Free(void* p); - - int32 GetMaxAllocation() const; - -private: - - char m_data[b2_stackSize]; - int32 m_index; - - int32 m_allocation; - int32 m_maxAllocation; - - b2StackEntry m_entries[b2_maxStackEntries]; - int32 m_entryCount; -}; - -#endif diff --git a/external/Box2D/Common/b2Timer.cpp b/external/Box2D/Common/b2Timer.cpp deleted file mode 100644 index b2bee94513..0000000000 --- a/external/Box2D/Common/b2Timer.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -#if defined(_WIN32) && !defined(SHP) - -float64 b2Timer::s_invFrequency = 0.0f; - -#include - -b2Timer::b2Timer() -{ - LARGE_INTEGER largeInteger; - - if (s_invFrequency == 0.0f) - { - QueryPerformanceFrequency(&largeInteger); - s_invFrequency = float64(largeInteger.QuadPart); - if (s_invFrequency > 0.0f) - { - s_invFrequency = 1000.0f / s_invFrequency; - } - } - - QueryPerformanceCounter(&largeInteger); - m_start = float64(largeInteger.QuadPart); -} - -void b2Timer::Reset() -{ - LARGE_INTEGER largeInteger; - QueryPerformanceCounter(&largeInteger); - m_start = float64(largeInteger.QuadPart); -} - -float32 b2Timer::GetMilliseconds() const -{ - LARGE_INTEGER largeInteger; - QueryPerformanceCounter(&largeInteger); - float64 count = float64(largeInteger.QuadPart); - float32 ms = float32(s_invFrequency * (count - m_start)); - return ms; -} - -#elif defined(__linux__) || defined (__APPLE__) - -#include - -b2Timer::b2Timer() -{ - Reset(); -} - -void b2Timer::Reset() -{ - timeval t; - gettimeofday(&t, 0); - m_start_sec = t.tv_sec; - m_start_msec = t.tv_usec * 0.001f; -} - -float32 b2Timer::GetMilliseconds() const -{ - timeval t; - gettimeofday(&t, 0); - return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; -} - -#else - -b2Timer::b2Timer() -{ -} - -void b2Timer::Reset() -{ -} - -float32 b2Timer::GetMilliseconds() const -{ - return 0.0f; -} - -#endif diff --git a/external/Box2D/Common/b2Timer.h b/external/Box2D/Common/b2Timer.h deleted file mode 100644 index 053a107a56..0000000000 --- a/external/Box2D/Common/b2Timer.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -/// Timer for profiling. This has platform specific code and may -/// not work on every platform. -class b2Timer -{ -public: - - /// Constructor - b2Timer(); - - /// Reset the timer. - void Reset(); - - /// Get the time since construction or the last reset. - float32 GetMilliseconds() const; - -private: - -#if defined(_WIN32) - float64 m_start; - static float64 s_invFrequency; -#elif defined(__linux__) || defined (__APPLE__) - unsigned long m_start_sec; - unsigned long m_start_msec; -#endif -}; diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp deleted file mode 100644 index 4ae4c41cd3..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); - return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); -} - -void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); - allocator->Free(contact, sizeof(b2ChainAndCircleContact)); -} - -b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) -: b2Contact(fixtureA, indexA, fixtureB, indexB) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); - b2EdgeShape edge; - chain->GetChildEdge(&edge, m_indexA); - b2CollideEdgeAndCircle( manifold, &edge, xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h deleted file mode 100644 index 1cf601a61f..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H -#define B2_CHAIN_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2ChainAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - ~b2ChainAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp deleted file mode 100644 index 8116c34d1b..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); - return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); -} - -void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); - allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); -} - -b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) -: b2Contact(fixtureA, indexA, fixtureB, indexB) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); - b2EdgeShape edge; - chain->GetChildEdge(&edge, m_indexA); - b2CollideEdgeAndPolygon( manifold, &edge, xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h deleted file mode 100644 index 381c49b844..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H -#define B2_CHAIN_AND_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2ChainAndPolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - ~b2ChainAndPolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp deleted file mode 100644 index 2436da5132..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2CircleContact)); - return new (mem) b2CircleContact(fixtureA, fixtureB); -} - -void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2CircleContact*)contact)->~b2CircleContact(); - allocator->Free(contact, sizeof(b2CircleContact)); -} - -b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) - : b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideCircles(manifold, - (b2CircleShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2CircleContact.h b/external/Box2D/Dynamics/Contacts/b2CircleContact.h deleted file mode 100644 index 6da056ae0d..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2CircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CIRCLE_CONTACT_H -#define B2_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2CircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2CircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2Contact.cpp b/external/Box2D/Dynamics/Contacts/b2Contact.cpp deleted file mode 100644 index 2389af6434..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2Contact.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; -bool b2Contact::s_initialized = false; - -void b2Contact::InitializeRegisters() -{ - AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); - AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); - AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); - AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); - AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); - AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); - AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); -} - -void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, - b2Shape::Type type1, b2Shape::Type type2) -{ - b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); - b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); - - s_registers[type1][type2].createFcn = createFcn; - s_registers[type1][type2].destroyFcn = destoryFcn; - s_registers[type1][type2].primary = true; - - if (type1 != type2) - { - s_registers[type2][type1].createFcn = createFcn; - s_registers[type2][type1].destroyFcn = destoryFcn; - s_registers[type2][type1].primary = false; - } -} - -b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - if (s_initialized == false) - { - InitializeRegisters(); - s_initialized = true; - } - - b2Shape::Type type1 = fixtureA->GetType(); - b2Shape::Type type2 = fixtureB->GetType(); - - b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); - b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); - - b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; - if (createFcn) - { - if (s_registers[type1][type2].primary) - { - return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); - } - else - { - return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); - } - } - else - { - return NULL; - } -} - -void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - b2Assert(s_initialized == true); - - if (contact->m_manifold.pointCount > 0) - { - contact->GetFixtureA()->GetBody()->SetAwake(true); - contact->GetFixtureB()->GetBody()->SetAwake(true); - } - - b2Shape::Type typeA = contact->GetFixtureA()->GetType(); - b2Shape::Type typeB = contact->GetFixtureB()->GetType(); - - b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); - b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); - - b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; - destroyFcn(contact, allocator); -} - -b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) -{ - m_flags = e_enabledFlag; - - m_fixtureA = fA; - m_fixtureB = fB; - - m_indexA = indexA; - m_indexB = indexB; - - m_manifold.pointCount = 0; - - m_prev = NULL; - m_next = NULL; - - m_nodeA.contact = NULL; - m_nodeA.prev = NULL; - m_nodeA.next = NULL; - m_nodeA.other = NULL; - - m_nodeB.contact = NULL; - m_nodeB.prev = NULL; - m_nodeB.next = NULL; - m_nodeB.other = NULL; - - m_toiCount = 0; - - m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); - m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); -} - -// Update the contact manifold and touching status. -// Note: do not assume the fixture AABBs are overlapping or are valid. -void b2Contact::Update(b2ContactListener* listener) -{ - b2Manifold oldManifold = m_manifold; - - // Re-enable this contact. - m_flags |= e_enabledFlag; - - bool touching = false; - bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; - - bool sensorA = m_fixtureA->IsSensor(); - bool sensorB = m_fixtureB->IsSensor(); - bool sensor = sensorA || sensorB; - - b2Body* bodyA = m_fixtureA->GetBody(); - b2Body* bodyB = m_fixtureB->GetBody(); - const b2Transform& xfA = bodyA->GetTransform(); - const b2Transform& xfB = bodyB->GetTransform(); - - // Is this contact a sensor? - if (sensor) - { - const b2Shape* shapeA = m_fixtureA->GetShape(); - const b2Shape* shapeB = m_fixtureB->GetShape(); - touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); - - // Sensors don't generate manifolds. - m_manifold.pointCount = 0; - } - else - { - Evaluate(&m_manifold, xfA, xfB); - touching = m_manifold.pointCount > 0; - - // Match old contact ids to new contact ids and copy the - // stored impulses to warm start the solver. - for (int32 i = 0; i < m_manifold.pointCount; ++i) - { - b2ManifoldPoint* mp2 = m_manifold.points + i; - mp2->normalImpulse = 0.0f; - mp2->tangentImpulse = 0.0f; - b2ContactID id2 = mp2->id; - - for (int32 j = 0; j < oldManifold.pointCount; ++j) - { - b2ManifoldPoint* mp1 = oldManifold.points + j; - - if (mp1->id.key == id2.key) - { - mp2->normalImpulse = mp1->normalImpulse; - mp2->tangentImpulse = mp1->tangentImpulse; - break; - } - } - } - - if (touching != wasTouching) - { - bodyA->SetAwake(true); - bodyB->SetAwake(true); - } - } - - if (touching) - { - m_flags |= e_touchingFlag; - } - else - { - m_flags &= ~e_touchingFlag; - } - - if (wasTouching == false && touching == true && listener) - { - listener->BeginContact(this); - } - - if (wasTouching == true && touching == false && listener) - { - listener->EndContact(this); - } - - if (sensor == false && touching && listener) - { - listener->PreSolve(this, &oldManifold); - } -} diff --git a/external/Box2D/Dynamics/Contacts/b2Contact.h b/external/Box2D/Dynamics/Contacts/b2Contact.h deleted file mode 100644 index 20d9403ce7..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2Contact.h +++ /dev/null @@ -1,331 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_H -#define B2_CONTACT_H - -#include -#include -#include -#include - -class b2Body; -class b2Contact; -class b2Fixture; -class b2World; -class b2BlockAllocator; -class b2StackAllocator; -class b2ContactListener; - -/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. -/// For example, anything slides on ice. -inline float32 b2MixFriction(float32 friction1, float32 friction2) -{ - return std::sqrt(friction1 * friction2); -} - -/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. -/// For example, a superball bounces on anything. -inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) -{ - return restitution1 > restitution2 ? restitution1 : restitution2; -} - -typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, - b2BlockAllocator* allocator); -typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); - -struct b2ContactRegister -{ - b2ContactCreateFcn* createFcn; - b2ContactDestroyFcn* destroyFcn; - bool primary; -}; - -/// A contact edge is used to connect bodies and contacts together -/// in a contact graph where each body is a node and each contact -/// is an edge. A contact edge belongs to a doubly linked list -/// maintained in each attached body. Each contact has two contact -/// nodes, one for each attached body. -struct b2ContactEdge -{ - b2Body* other; ///< provides quick access to the other body attached. - b2Contact* contact; ///< the contact - b2ContactEdge* prev; ///< the previous contact edge in the body's contact list - b2ContactEdge* next; ///< the next contact edge in the body's contact list -}; - -/// The class manages contact between two shapes. A contact exists for each overlapping -/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist -/// that has no contact points. -class b2Contact -{ -public: - - /// Get the contact manifold. Do not modify the manifold unless you understand the - /// internals of Box2D. - b2Manifold* GetManifold(); - const b2Manifold* GetManifold() const; - - /// Get the world manifold. - void GetWorldManifold(b2WorldManifold* worldManifold) const; - - /// Is this contact touching? - bool IsTouching() const; - - /// Enable/disable this contact. This can be used inside the pre-solve - /// contact listener. The contact is only disabled for the current - /// time step (or sub-step in continuous collisions). - void SetEnabled(bool flag); - - /// Has this contact been disabled? - bool IsEnabled() const; - - /// Get the next contact in the world's contact list. - b2Contact* GetNext(); - const b2Contact* GetNext() const; - - /// Get fixture A in this contact. - b2Fixture* GetFixtureA(); - const b2Fixture* GetFixtureA() const; - - /// Get the child primitive index for fixture A. - int32 GetChildIndexA() const; - - /// Get fixture B in this contact. - b2Fixture* GetFixtureB(); - const b2Fixture* GetFixtureB() const; - - /// Get the child primitive index for fixture B. - int32 GetChildIndexB() const; - - /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. - /// This value persists until set or reset. - void SetFriction(float32 friction); - - /// Get the friction. - float32 GetFriction() const; - - /// Reset the friction mixture to the default value. - void ResetFriction(); - - /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. - /// The value persists until you set or reset. - void SetRestitution(float32 restitution); - - /// Get the restitution. - float32 GetRestitution() const; - - /// Reset the restitution to the default value. - void ResetRestitution(); - - /// Evaluate this contact with your own manifold and transforms. - virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; - -protected: - friend class b2ContactManager; - friend class b2World; - friend class b2ContactSolver; - friend class b2Body; - friend class b2Fixture; - - // Flags stored in m_flags - enum - { - // Used when crawling contact graph when forming islands. - e_islandFlag = 0x0001, - - // Set when the shapes are touching. - e_touchingFlag = 0x0002, - - // This contact can be disabled (by user) - e_enabledFlag = 0x0004, - - // This contact needs filtering because a fixture filter was changed. - e_filterFlag = 0x0008, - - // This bullet contact had a TOI event - e_bulletHitFlag = 0x0010, - - // This contact has a valid TOI in m_toi - e_toiFlag = 0x0020 - }; - - /// Flag this contact for filtering. Filtering will occur the next time step. - void FlagForFiltering(); - - static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, - b2Shape::Type typeA, b2Shape::Type typeB); - static void InitializeRegisters(); - static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} - b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - virtual ~b2Contact() {} - - void Update(b2ContactListener* listener); - - static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; - static bool s_initialized; - - uint32 m_flags; - - // World pool and list pointers. - b2Contact* m_prev; - b2Contact* m_next; - - // Nodes for connecting bodies. - b2ContactEdge m_nodeA; - b2ContactEdge m_nodeB; - - b2Fixture* m_fixtureA; - b2Fixture* m_fixtureB; - - int32 m_indexA; - int32 m_indexB; - - b2Manifold m_manifold; - - int32 m_toiCount; - float32 m_toi; - - float32 m_friction; - float32 m_restitution; -}; - -inline b2Manifold* b2Contact::GetManifold() -{ - return &m_manifold; -} - -inline const b2Manifold* b2Contact::GetManifold() const -{ - return &m_manifold; -} - -inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const -{ - const b2Body* bodyA = m_fixtureA->GetBody(); - const b2Body* bodyB = m_fixtureB->GetBody(); - const b2Shape* shapeA = m_fixtureA->GetShape(); - const b2Shape* shapeB = m_fixtureB->GetShape(); - - worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); -} - -inline void b2Contact::SetEnabled(bool flag) -{ - if (flag) - { - m_flags |= e_enabledFlag; - } - else - { - m_flags &= ~e_enabledFlag; - } -} - -inline bool b2Contact::IsEnabled() const -{ - return (m_flags & e_enabledFlag) == e_enabledFlag; -} - -inline bool b2Contact::IsTouching() const -{ - return (m_flags & e_touchingFlag) == e_touchingFlag; -} - -inline b2Contact* b2Contact::GetNext() -{ - return m_next; -} - -inline const b2Contact* b2Contact::GetNext() const -{ - return m_next; -} - -inline b2Fixture* b2Contact::GetFixtureA() -{ - return m_fixtureA; -} - -inline const b2Fixture* b2Contact::GetFixtureA() const -{ - return m_fixtureA; -} - -inline b2Fixture* b2Contact::GetFixtureB() -{ - return m_fixtureB; -} - -inline int32 b2Contact::GetChildIndexA() const -{ - return m_indexA; -} - -inline const b2Fixture* b2Contact::GetFixtureB() const -{ - return m_fixtureB; -} - -inline int32 b2Contact::GetChildIndexB() const -{ - return m_indexB; -} - -inline void b2Contact::FlagForFiltering() -{ - m_flags |= e_filterFlag; -} - -inline void b2Contact::SetFriction(float32 friction) -{ - m_friction = friction; -} - -inline float32 b2Contact::GetFriction() const -{ - return m_friction; -} - -inline void b2Contact::ResetFriction() -{ - m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); -} - -inline void b2Contact::SetRestitution(float32 restitution) -{ - m_restitution = restitution; -} - -inline float32 b2Contact::GetRestitution() const -{ - return m_restitution; -} - -inline void b2Contact::ResetRestitution() -{ - m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); -} - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp b/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp deleted file mode 100644 index 0dc740342a..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp +++ /dev/null @@ -1,832 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 - -#include -#include -#include -#include -#include - -#define B2_DEBUG_SOLVER 0 - -struct b2ContactPositionConstraint -{ - b2Vec2 localPoints[b2_maxManifoldPoints]; - b2Vec2 localNormal; - b2Vec2 localPoint; - int32 indexA; - int32 indexB; - float32 invMassA, invMassB; - b2Vec2 localCenterA, localCenterB; - float32 invIA, invIB; - b2Manifold::Type type; - float32 radiusA, radiusB; - int32 pointCount; -}; - -b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) -{ - m_step = def->step; - m_allocator = def->allocator; - m_count = def->count; - m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); - m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); - m_positions = def->positions; - m_velocities = def->velocities; - m_contacts = def->contacts; - - // Initialize position independent portions of the constraints. - for (int32 i = 0; i < m_count; ++i) - { - b2Contact* contact = m_contacts[i]; - - b2Fixture* fixtureA = contact->m_fixtureA; - b2Fixture* fixtureB = contact->m_fixtureB; - b2Shape* shapeA = fixtureA->GetShape(); - b2Shape* shapeB = fixtureB->GetShape(); - float32 radiusA = shapeA->m_radius; - float32 radiusB = shapeB->m_radius; - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - b2Manifold* manifold = contact->GetManifold(); - - int32 pointCount = manifold->pointCount; - b2Assert(pointCount > 0); - - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - vc->friction = contact->m_friction; - vc->restitution = contact->m_restitution; - vc->indexA = bodyA->m_islandIndex; - vc->indexB = bodyB->m_islandIndex; - vc->invMassA = bodyA->m_invMass; - vc->invMassB = bodyB->m_invMass; - vc->invIA = bodyA->m_invI; - vc->invIB = bodyB->m_invI; - vc->contactIndex = i; - vc->pointCount = pointCount; - vc->K.SetZero(); - vc->normalMass.SetZero(); - - b2ContactPositionConstraint* pc = m_positionConstraints + i; - pc->indexA = bodyA->m_islandIndex; - pc->indexB = bodyB->m_islandIndex; - pc->invMassA = bodyA->m_invMass; - pc->invMassB = bodyB->m_invMass; - pc->localCenterA = bodyA->m_sweep.localCenter; - pc->localCenterB = bodyB->m_sweep.localCenter; - pc->invIA = bodyA->m_invI; - pc->invIB = bodyB->m_invI; - pc->localNormal = manifold->localNormal; - pc->localPoint = manifold->localPoint; - pc->pointCount = pointCount; - pc->radiusA = radiusA; - pc->radiusB = radiusB; - pc->type = manifold->type; - - for (int32 j = 0; j < pointCount; ++j) - { - b2ManifoldPoint* cp = manifold->points + j; - b2VelocityConstraintPoint* vcp = vc->points + j; - - if (m_step.warmStarting) - { - vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; - vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; - } - else - { - vcp->normalImpulse = 0.0f; - vcp->tangentImpulse = 0.0f; - } - - vcp->rA.SetZero(); - vcp->rB.SetZero(); - vcp->normalMass = 0.0f; - vcp->tangentMass = 0.0f; - vcp->velocityBias = 0.0f; - - pc->localPoints[j] = cp->localPoint; - } - } -} - -b2ContactSolver::~b2ContactSolver() -{ - m_allocator->Free(m_velocityConstraints); - m_allocator->Free(m_positionConstraints); -} - -// Initialize position dependent portions of the velocity constraints. -void b2ContactSolver::InitializeVelocityConstraints() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - float32 radiusA = pc->radiusA; - float32 radiusB = pc->radiusB; - b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - - float32 mA = vc->invMassA; - float32 mB = vc->invMassB; - float32 iA = vc->invIA; - float32 iB = vc->invIB; - b2Vec2 localCenterA = pc->localCenterA; - b2Vec2 localCenterB = pc->localCenterB; - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Assert(manifold->pointCount > 0); - - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2WorldManifold worldManifold; - worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); - - vc->normal = worldManifold.normal; - - int32 pointCount = vc->pointCount; - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - - vcp->rA = worldManifold.points[j] - cA; - vcp->rB = worldManifold.points[j] - cB; - - float32 rnA = b2Cross(vcp->rA, vc->normal); - float32 rnB = b2Cross(vcp->rB, vc->normal); - - float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; - - b2Vec2 tangent = b2Cross(vc->normal, 1.0f); - - float32 rtA = b2Cross(vcp->rA, tangent); - float32 rtB = b2Cross(vcp->rB, tangent); - - float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; - - vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; - - // Setup a velocity bias for restitution. - vcp->velocityBias = 0.0f; - float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); - if (vRel < -b2_velocityThreshold) - { - vcp->velocityBias = -vc->restitution * vRel; - } - } - - // If we have two points, then prepare the block solver. - if (vc->pointCount == 2) - { - b2VelocityConstraintPoint* vcp1 = vc->points + 0; - b2VelocityConstraintPoint* vcp2 = vc->points + 1; - - float32 rn1A = b2Cross(vcp1->rA, vc->normal); - float32 rn1B = b2Cross(vcp1->rB, vc->normal); - float32 rn2A = b2Cross(vcp2->rA, vc->normal); - float32 rn2B = b2Cross(vcp2->rB, vc->normal); - - float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; - float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; - float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; - - // Ensure a reasonable condition number. - const float32 k_maxConditionNumber = 1000.0f; - if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) - { - // K is safe to invert. - vc->K.ex.Set(k11, k12); - vc->K.ey.Set(k12, k22); - vc->normalMass = vc->K.GetInverse(); - } - else - { - // The constraints are redundant, just use one. - // TODO_ERIN use deepest? - vc->pointCount = 1; - } - } - } -} - -void b2ContactSolver::WarmStart() -{ - // Warm start. - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - float32 mA = vc->invMassA; - float32 iA = vc->invIA; - float32 mB = vc->invMassB; - float32 iB = vc->invIB; - int32 pointCount = vc->pointCount; - - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Vec2 normal = vc->normal; - b2Vec2 tangent = b2Cross(normal, 1.0f); - - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; - wA -= iA * b2Cross(vcp->rA, P); - vA -= mA * P; - wB += iB * b2Cross(vcp->rB, P); - vB += mB * P; - } - - m_velocities[indexA].v = vA; - m_velocities[indexA].w = wA; - m_velocities[indexB].v = vB; - m_velocities[indexB].w = wB; - } -} - -void b2ContactSolver::SolveVelocityConstraints() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - float32 mA = vc->invMassA; - float32 iA = vc->invIA; - float32 mB = vc->invMassB; - float32 iB = vc->invIB; - int32 pointCount = vc->pointCount; - - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Vec2 normal = vc->normal; - b2Vec2 tangent = b2Cross(normal, 1.0f); - float32 friction = vc->friction; - - b2Assert(pointCount == 1 || pointCount == 2); - - // Solve tangent constraints first because non-penetration is more important - // than friction. - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - - // Relative velocity at contact - b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); - - // Compute tangent force - float32 vt = b2Dot(dv, tangent); - float32 lambda = vcp->tangentMass * (-vt); - - // b2Clamp the accumulated force - float32 maxFriction = friction * vcp->normalImpulse; - float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); - lambda = newImpulse - vcp->tangentImpulse; - vcp->tangentImpulse = newImpulse; - - // Apply contact impulse - b2Vec2 P = lambda * tangent; - - vA -= mA * P; - wA -= iA * b2Cross(vcp->rA, P); - - vB += mB * P; - wB += iB * b2Cross(vcp->rB, P); - } - - // Solve normal constraints - if (vc->pointCount == 1) - { - b2VelocityConstraintPoint* vcp = vc->points + 0; - - // Relative velocity at contact - b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); - - // Compute normal impulse - float32 vn = b2Dot(dv, normal); - float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); - - // b2Clamp the accumulated impulse - float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); - lambda = newImpulse - vcp->normalImpulse; - vcp->normalImpulse = newImpulse; - - // Apply contact impulse - b2Vec2 P = lambda * normal; - vA -= mA * P; - wA -= iA * b2Cross(vcp->rA, P); - - vB += mB * P; - wB += iB * b2Cross(vcp->rB, P); - } - else - { - // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). - // Build the mini LCP for this contact patch - // - // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 - // - // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) - // b = vn0 - velocityBias - // - // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i - // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases - // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid - // solution that satisfies the problem is chosen. - // - // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires - // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). - // - // Substitute: - // - // x = a + d - // - // a := old total impulse - // x := new total impulse - // d := incremental impulse - // - // For the current iteration we extend the formula for the incremental impulse - // to compute the new total impulse: - // - // vn = A * d + b - // = A * (x - a) + b - // = A * x + b - A * a - // = A * x + b' - // b' = b - A * a; - - b2VelocityConstraintPoint* cp1 = vc->points + 0; - b2VelocityConstraintPoint* cp2 = vc->points + 1; - - b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); - b2Assert(a.x >= 0.0f && a.y >= 0.0f); - - // Relative velocity at contact - b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - float32 vn1 = b2Dot(dv1, normal); - float32 vn2 = b2Dot(dv2, normal); - - b2Vec2 b; - b.x = vn1 - cp1->velocityBias; - b.y = vn2 - cp2->velocityBias; - - // Compute b' - b -= b2Mul(vc->K, a); - - const float32 k_errorTol = 1e-3f; - B2_NOT_USED(k_errorTol); - - for (;;) - { - // - // Case 1: vn = 0 - // - // 0 = A * x + b' - // - // Solve for x: - // - // x = - inv(A) * b' - // - b2Vec2 x = - b2Mul(vc->normalMass, b); - - if (x.x >= 0.0f && x.y >= 0.0f) - { - // Get the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - vn1 = b2Dot(dv1, normal); - vn2 = b2Dot(dv2, normal); - - b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); - b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); -#endif - break; - } - - // - // Case 2: vn1 = 0 and x2 = 0 - // - // 0 = a11 * x1 + a12 * 0 + b1' - // vn2 = a21 * x1 + a22 * 0 + b2' - // - x.x = - cp1->normalMass * b.x; - x.y = 0.0f; - vn1 = 0.0f; - vn2 = vc->K.ex.y * x.x + b.y; - - if (x.x >= 0.0f && vn2 >= 0.0f) - { - // Get the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - - // Compute normal velocity - vn1 = b2Dot(dv1, normal); - - b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); -#endif - break; - } - - - // - // Case 3: vn2 = 0 and x1 = 0 - // - // vn1 = a11 * 0 + a12 * x2 + b1' - // 0 = a21 * 0 + a22 * x2 + b2' - // - x.x = 0.0f; - x.y = - cp2->normalMass * b.y; - vn1 = vc->K.ey.x * x.y + b.x; - vn2 = 0.0f; - - if (x.y >= 0.0f && vn1 >= 0.0f) - { - // Resubstitute for the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - vn2 = b2Dot(dv2, normal); - - b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); -#endif - break; - } - - // - // Case 4: x1 = 0 and x2 = 0 - // - // vn1 = b1 - // vn2 = b2; - x.x = 0.0f; - x.y = 0.0f; - vn1 = b.x; - vn2 = b.y; - - if (vn1 >= 0.0f && vn2 >= 0.0f ) - { - // Resubstitute for the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - - break; - } - - // No solution, give up. This is hit sometimes, but it doesn't seem to matter. - break; - } - } - - m_velocities[indexA].v = vA; - m_velocities[indexA].w = wA; - m_velocities[indexB].v = vB; - m_velocities[indexB].w = wB; - } -} - -void b2ContactSolver::StoreImpulses() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); - - for (int32 j = 0; j < vc->pointCount; ++j) - { - manifold->points[j].normalImpulse = vc->points[j].normalImpulse; - manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; - } - } -} - -struct b2PositionSolverManifold -{ - void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) - { - b2Assert(pc->pointCount > 0); - - switch (pc->type) - { - case b2Manifold::e_circles: - { - b2Vec2 pointA = b2Mul(xfA, pc->localPoint); - b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); - normal = pointB - pointA; - normal.Normalize(); - point = 0.5f * (pointA + pointB); - separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; - } - break; - - case b2Manifold::e_faceA: - { - normal = b2Mul(xfA.q, pc->localNormal); - b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); - - b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); - separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; - point = clipPoint; - } - break; - - case b2Manifold::e_faceB: - { - normal = b2Mul(xfB.q, pc->localNormal); - b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); - - b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); - separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; - point = clipPoint; - - // Ensure normal points from A to B - normal = -normal; - } - break; - } - } - - b2Vec2 normal; - b2Vec2 point; - float32 separation; -}; - -// Sequential solver. -bool b2ContactSolver::SolvePositionConstraints() -{ - float32 minSeparation = 0.0f; - - for (int32 i = 0; i < m_count; ++i) - { - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - int32 indexA = pc->indexA; - int32 indexB = pc->indexB; - b2Vec2 localCenterA = pc->localCenterA; - float32 mA = pc->invMassA; - float32 iA = pc->invIA; - b2Vec2 localCenterB = pc->localCenterB; - float32 mB = pc->invMassB; - float32 iB = pc->invIB; - int32 pointCount = pc->pointCount; - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - - // Solve normal constraints - for (int32 j = 0; j < pointCount; ++j) - { - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2PositionSolverManifold psm; - psm.Initialize(pc, xfA, xfB, j); - b2Vec2 normal = psm.normal; - - b2Vec2 point = psm.point; - float32 separation = psm.separation; - - b2Vec2 rA = point - cA; - b2Vec2 rB = point - cB; - - // Track max constraint error. - minSeparation = b2Min(minSeparation, separation); - - // Prevent large corrections and allow slop. - float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); - - // Compute the effective mass. - float32 rnA = b2Cross(rA, normal); - float32 rnB = b2Cross(rB, normal); - float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - // Compute normal impulse - float32 impulse = K > 0.0f ? - C / K : 0.0f; - - b2Vec2 P = impulse * normal; - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - - m_positions[indexA].c = cA; - m_positions[indexA].a = aA; - - m_positions[indexB].c = cB; - m_positions[indexB].a = aB; - } - - // We can't expect minSpeparation >= -b2_linearSlop because we don't - // push the separation above -b2_linearSlop. - return minSeparation >= -3.0f * b2_linearSlop; -} - -// Sequential position solver for position constraints. -bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) -{ - float32 minSeparation = 0.0f; - - for (int32 i = 0; i < m_count; ++i) - { - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - int32 indexA = pc->indexA; - int32 indexB = pc->indexB; - b2Vec2 localCenterA = pc->localCenterA; - b2Vec2 localCenterB = pc->localCenterB; - int32 pointCount = pc->pointCount; - - float32 mA = 0.0f; - float32 iA = 0.0f; - if (indexA == toiIndexA || indexA == toiIndexB) - { - mA = pc->invMassA; - iA = pc->invIA; - } - - float32 mB = pc->invMassB; - float32 iB = pc->invIB; - if (indexB == toiIndexA || indexB == toiIndexB) - { - mB = pc->invMassB; - iB = pc->invIB; - } - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - - // Solve normal constraints - for (int32 j = 0; j < pointCount; ++j) - { - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2PositionSolverManifold psm; - psm.Initialize(pc, xfA, xfB, j); - b2Vec2 normal = psm.normal; - - b2Vec2 point = psm.point; - float32 separation = psm.separation; - - b2Vec2 rA = point - cA; - b2Vec2 rB = point - cB; - - // Track max constraint error. - minSeparation = b2Min(minSeparation, separation); - - // Prevent large corrections and allow slop. - float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); - - // Compute the effective mass. - float32 rnA = b2Cross(rA, normal); - float32 rnB = b2Cross(rB, normal); - float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - // Compute normal impulse - float32 impulse = K > 0.0f ? - C / K : 0.0f; - - b2Vec2 P = impulse * normal; - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - - m_positions[indexA].c = cA; - m_positions[indexA].a = aA; - - m_positions[indexB].c = cB; - m_positions[indexB].a = aB; - } - - // We can't expect minSpeparation >= -b2_linearSlop because we don't - // push the separation above -b2_linearSlop. - return minSeparation >= -1.5f * b2_linearSlop; -} diff --git a/external/Box2D/Dynamics/Contacts/b2ContactSolver.h b/external/Box2D/Dynamics/Contacts/b2ContactSolver.h deleted file mode 100644 index aef1987a9e..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2ContactSolver.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_SOLVER_H -#define B2_CONTACT_SOLVER_H - -#include -#include -#include - -class b2Contact; -class b2Body; -class b2StackAllocator; -struct b2ContactPositionConstraint; - -struct b2VelocityConstraintPoint -{ - b2Vec2 rA; - b2Vec2 rB; - float32 normalImpulse; - float32 tangentImpulse; - float32 normalMass; - float32 tangentMass; - float32 velocityBias; -}; - -struct b2ContactVelocityConstraint -{ - b2VelocityConstraintPoint points[b2_maxManifoldPoints]; - b2Vec2 normal; - b2Mat22 normalMass; - b2Mat22 K; - int32 indexA; - int32 indexB; - float32 invMassA, invMassB; - float32 invIA, invIB; - float32 friction; - float32 restitution; - int32 pointCount; - int32 contactIndex; -}; - -struct b2ContactSolverDef -{ - b2TimeStep step; - b2Contact** contacts; - int32 count; - b2Position* positions; - b2Velocity* velocities; - b2StackAllocator* allocator; -}; - -class b2ContactSolver -{ -public: - b2ContactSolver(b2ContactSolverDef* def); - ~b2ContactSolver(); - - void InitializeVelocityConstraints(); - - void WarmStart(); - void SolveVelocityConstraints(); - void StoreImpulses(); - - bool SolvePositionConstraints(); - bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); - - b2TimeStep m_step; - b2Position* m_positions; - b2Velocity* m_velocities; - b2StackAllocator* m_allocator; - b2ContactPositionConstraint* m_positionConstraints; - b2ContactVelocityConstraint* m_velocityConstraints; - b2Contact** m_contacts; - int m_count; -}; - -#endif - diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp deleted file mode 100644 index aade42880a..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include - -#include -using namespace std; - -b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); - return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); -} - -void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); - allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); -} - -b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideEdgeAndCircle( manifold, - (b2EdgeShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h deleted file mode 100644 index 70771ec536..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H -#define B2_EDGE_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2EdgeAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2EdgeAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp deleted file mode 100644 index 04ce394107..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include - -#include -using namespace std; - -b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); - return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); -} - -void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); - allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); -} - -b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideEdgeAndPolygon( manifold, - (b2EdgeShape*)m_fixtureA->GetShape(), xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h deleted file mode 100644 index f65f3acca9..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_EDGE_AND_POLYGON_CONTACT_H -#define B2_EDGE_AND_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2EdgeAndPolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2EdgeAndPolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp deleted file mode 100644 index 961b26f38a..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include - -#include -using namespace std; - -b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); - return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); -} - -void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); - allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); -} - -b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollidePolygonAndCircle( manifold, - (b2PolygonShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h deleted file mode 100644 index 7b1a5288b4..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H -#define B2_POLYGON_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2PolygonAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2PolygonAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp deleted file mode 100644 index a2884a440d..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2PolygonContact)); - return new (mem) b2PolygonContact(fixtureA, fixtureB); -} - -void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2PolygonContact*)contact)->~b2PolygonContact(); - allocator->Free(contact, sizeof(b2PolygonContact)); -} - -b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) - : b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollidePolygons( manifold, - (b2PolygonShape*)m_fixtureA->GetShape(), xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonContact.h b/external/Box2D/Dynamics/Contacts/b2PolygonContact.h deleted file mode 100644 index 302684232a..0000000000 --- a/external/Box2D/Dynamics/Contacts/b2PolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_CONTACT_H -#define B2_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2PolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2PolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp deleted file mode 100644 index b2d4bd006c..0000000000 --- a/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// 1-D constrained system -// m (v2 - v1) = lambda -// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. -// x2 = x1 + h * v2 - -// 1-D mass-damper-spring system -// m (v2 - v1) + h * d * v2 + h * k * - -// C = norm(p2 - p1) - L -// u = (p2 - p1) / norm(p2 - p1) -// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) -// J = [-u -cross(r1, u) u cross(r2, u)] -// K = J * invM * JT -// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 - -void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, - const b2Vec2& anchor1, const b2Vec2& anchor2) -{ - bodyA = b1; - bodyB = b2; - localAnchorA = bodyA->GetLocalPoint(anchor1); - localAnchorB = bodyB->GetLocalPoint(anchor2); - b2Vec2 d = anchor2 - anchor1; - length = d.Length(); -} - -b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_length = def->length; - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - m_impulse = 0.0f; - m_gamma = 0.0f; - m_bias = 0.0f; -} - -void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - m_u = cB + m_rB - cA - m_rA; - - // Handle singularity. - float32 length = m_u.Length(); - if (length > b2_linearSlop) - { - m_u *= 1.0f / length; - } - else - { - m_u.Set(0.0f, 0.0f); - } - - float32 crAu = b2Cross(m_rA, m_u); - float32 crBu = b2Cross(m_rB, m_u); - float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; - - // Compute the effective mass matrix. - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - - if (m_frequencyHz > 0.0f) - { - float32 C = length - m_length; - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m_mass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m_mass * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; - m_bias = C * h * k * m_gamma; - - invMass += m_gamma; - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - } - else - { - m_gamma = 0.0f; - m_bias = 0.0f; - } - - if (data.step.warmStarting) - { - // Scale the impulse to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = dot(u, v + cross(w, r)) - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - float32 Cdot = b2Dot(m_u, vpB - vpA); - - float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); - m_impulse += impulse; - - b2Vec2 P = impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) -{ - if (m_frequencyHz > 0.0f) - { - // There is no position correction for soft distance constraints. - return true; - } - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 u = cB + rB - cA - rA; - - float32 length = u.Normalize(); - float32 C = length - m_length; - C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); - - float32 impulse = -m_mass * C; - b2Vec2 P = impulse * u; - - cA -= m_invMassA * P; - aA -= m_invIA * b2Cross(rA, P); - cB += m_invMassB * P; - aB += m_invIB * b2Cross(rB, P); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return b2Abs(C) < b2_linearSlop; -} - -b2Vec2 b2DistanceJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2DistanceJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 F = (inv_dt * m_impulse) * m_u; - return F; -} - -float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -void b2DistanceJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2DistanceJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.length = %.15lef;\n", m_length); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2DistanceJoint.h b/external/Box2D/Dynamics/Joints/b2DistanceJoint.h deleted file mode 100644 index fc11476ff9..0000000000 --- a/external/Box2D/Dynamics/Joints/b2DistanceJoint.h +++ /dev/null @@ -1,169 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_DISTANCE_JOINT_H -#define B2_DISTANCE_JOINT_H - -#include - -/// Distance joint definition. This requires defining an -/// anchor point on both bodies and the non-zero length of the -/// distance joint. The definition uses local anchor points -/// so that the initial configuration can violate the constraint -/// slightly. This helps when saving and loading a game. -/// @warning Do not use a zero or short length. -struct b2DistanceJointDef : public b2JointDef -{ - b2DistanceJointDef() - { - type = e_distanceJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - length = 1.0f; - frequencyHz = 0.0f; - dampingRatio = 0.0f; - } - - /// Initialize the bodies, anchors, and length using the world - /// anchors. - void Initialize(b2Body* bodyA, b2Body* bodyB, - const b2Vec2& anchorA, const b2Vec2& anchorB); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The natural length between the anchor points. - float32 length; - - /// The mass-spring-damper frequency in Hertz. A value of 0 - /// disables softness. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A distance joint constrains two points on two bodies -/// to remain at a fixed distance from each other. You can view -/// this as a massless, rigid rod. -class b2DistanceJoint : public b2Joint -{ -public: - - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - /// Get the reaction force given the inverse time step. - /// Unit is N. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Get the reaction torque given the inverse time step. - /// Unit is N*m. This is always zero for a distance joint. - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set/get the natural length. - /// Manipulating the length can lead to non-physical behavior when the frequency is zero. - void SetLength(float32 length); - float32 GetLength() const; - - /// Set/get frequency in Hz. - void SetFrequency(float32 hz); - float32 GetFrequency() const; - - /// Set/get damping ratio. - void SetDampingRatio(float32 ratio); - float32 GetDampingRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2DistanceJoint(const b2DistanceJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_bias; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_gamma; - float32 m_impulse; - float32 m_length; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_u; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; -}; - -inline void b2DistanceJoint::SetLength(float32 length) -{ - m_length = length; -} - -inline float32 b2DistanceJoint::GetLength() const -{ - return m_length; -} - -inline void b2DistanceJoint::SetFrequency(float32 hz) -{ - m_frequencyHz = hz; -} - -inline float32 b2DistanceJoint::GetFrequency() const -{ - return m_frequencyHz; -} - -inline void b2DistanceJoint::SetDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -inline float32 b2DistanceJoint::GetDampingRatio() const -{ - return m_dampingRatio; -} - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp deleted file mode 100644 index 6e6018db10..0000000000 --- a/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Angle constraint -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); -} - -b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_linearImpulse.SetZero(); - m_angularImpulse = 0.0f; - - m_maxForce = def->maxForce; - m_maxTorque = def->maxTorque; -} - -void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective mass matrix. - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat22 K; - K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; - K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; - K.ey.x = K.ex.y; - K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; - - m_linearMass = K.GetInverse(); - - m_angularMass = iA + iB; - if (m_angularMass > 0.0f) - { - m_angularMass = 1.0f / m_angularMass; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_linearImpulse *= data.step.dtRatio; - m_angularImpulse *= data.step.dtRatio; - - b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); - } - else - { - m_linearImpulse.SetZero(); - m_angularImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - float32 h = data.step.dt; - - // Solve angular friction - { - float32 Cdot = wB - wA; - float32 impulse = -m_angularMass * Cdot; - - float32 oldImpulse = m_angularImpulse; - float32 maxImpulse = h * m_maxTorque; - m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_angularImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve linear friction - { - b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - - b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); - b2Vec2 oldImpulse = m_linearImpulse; - m_linearImpulse += impulse; - - float32 maxImpulse = h * m_maxForce; - - if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) - { - m_linearImpulse.Normalize(); - m_linearImpulse *= maxImpulse; - } - - impulse = m_linearImpulse - oldImpulse; - - vA -= mA * impulse; - wA -= iA * b2Cross(m_rA, impulse); - - vB += mB * impulse; - wB += iB * b2Cross(m_rB, impulse); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) -{ - B2_NOT_USED(data); - - return true; -} - -b2Vec2 b2FrictionJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2FrictionJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * m_linearImpulse; -} - -float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_angularImpulse; -} - -void b2FrictionJoint::SetMaxForce(float32 force) -{ - b2Assert(b2IsValid(force) && force >= 0.0f); - m_maxForce = force; -} - -float32 b2FrictionJoint::GetMaxForce() const -{ - return m_maxForce; -} - -void b2FrictionJoint::SetMaxTorque(float32 torque) -{ - b2Assert(b2IsValid(torque) && torque >= 0.0f); - m_maxTorque = torque; -} - -float32 b2FrictionJoint::GetMaxTorque() const -{ - return m_maxTorque; -} - -void b2FrictionJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2FrictionJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); - b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2FrictionJoint.h b/external/Box2D/Dynamics/Joints/b2FrictionJoint.h deleted file mode 100644 index 3ee40c6298..0000000000 --- a/external/Box2D/Dynamics/Joints/b2FrictionJoint.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_FRICTION_JOINT_H -#define B2_FRICTION_JOINT_H - -#include - -/// Friction joint definition. -struct b2FrictionJointDef : public b2JointDef -{ - b2FrictionJointDef() - { - type = e_frictionJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - maxForce = 0.0f; - maxTorque = 0.0f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The maximum friction force in N. - float32 maxForce; - - /// The maximum friction torque in N-m. - float32 maxTorque; -}; - -/// Friction joint. This is used for top-down friction. -/// It provides 2D translational friction and angular friction. -class b2FrictionJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set the maximum friction force in N. - void SetMaxForce(float32 force); - - /// Get the maximum friction force in N. - float32 GetMaxForce() const; - - /// Set the maximum friction torque in N*m. - void SetMaxTorque(float32 torque); - - /// Get the maximum friction torque in N*m. - float32 GetMaxTorque() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - - b2FrictionJoint(const b2FrictionJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - - // Solver shared - b2Vec2 m_linearImpulse; - float32 m_angularImpulse; - float32 m_maxForce; - float32 m_maxTorque; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat22 m_linearMass; - float32 m_angularMass; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2GearJoint.cpp b/external/Box2D/Dynamics/Joints/b2GearJoint.cpp deleted file mode 100644 index 9741cdd5a4..0000000000 --- a/external/Box2D/Dynamics/Joints/b2GearJoint.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* -* Copyright (c) 2007-2011 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 -#include -#include -#include -#include - -// Gear Joint: -// C0 = (coordinate1 + ratio * coordinate2)_initial -// C = (coordinate1 + ratio * coordinate2) - C0 = 0 -// J = [J1 ratio * J2] -// K = J * invM * JT -// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T -// -// Revolute: -// coordinate = rotation -// Cdot = angularVelocity -// J = [0 0 1] -// K = J * invM * JT = invI -// -// Prismatic: -// coordinate = dot(p - pg, ug) -// Cdot = dot(v + cross(w, r), ug) -// J = [ug cross(r, ug)] -// K = J * invM * JT = invMass + invI * cross(r, ug)^2 - -b2GearJoint::b2GearJoint(const b2GearJointDef* def) -: b2Joint(def) -{ - m_joint1 = def->joint1; - m_joint2 = def->joint2; - - m_typeA = m_joint1->GetType(); - m_typeB = m_joint2->GetType(); - - b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); - b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); - - float32 coordinateA, coordinateB; - - // TODO_ERIN there might be some problem with the joint edges in b2Joint. - - m_bodyC = m_joint1->GetBodyA(); - m_bodyA = m_joint1->GetBodyB(); - - // Get geometry of joint1 - b2Transform xfA = m_bodyA->m_xf; - float32 aA = m_bodyA->m_sweep.a; - b2Transform xfC = m_bodyC->m_xf; - float32 aC = m_bodyC->m_sweep.a; - - if (m_typeA == e_revoluteJoint) - { - b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; - m_localAnchorC = revolute->m_localAnchorA; - m_localAnchorA = revolute->m_localAnchorB; - m_referenceAngleA = revolute->m_referenceAngle; - m_localAxisC.SetZero(); - - coordinateA = aA - aC - m_referenceAngleA; - } - else - { - b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; - m_localAnchorC = prismatic->m_localAnchorA; - m_localAnchorA = prismatic->m_localAnchorB; - m_referenceAngleA = prismatic->m_referenceAngle; - m_localAxisC = prismatic->m_localXAxisA; - - b2Vec2 pC = m_localAnchorC; - b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); - coordinateA = b2Dot(pA - pC, m_localAxisC); - } - - m_bodyD = m_joint2->GetBodyA(); - m_bodyB = m_joint2->GetBodyB(); - - // Get geometry of joint2 - b2Transform xfB = m_bodyB->m_xf; - float32 aB = m_bodyB->m_sweep.a; - b2Transform xfD = m_bodyD->m_xf; - float32 aD = m_bodyD->m_sweep.a; - - if (m_typeB == e_revoluteJoint) - { - b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; - m_localAnchorD = revolute->m_localAnchorA; - m_localAnchorB = revolute->m_localAnchorB; - m_referenceAngleB = revolute->m_referenceAngle; - m_localAxisD.SetZero(); - - coordinateB = aB - aD - m_referenceAngleB; - } - else - { - b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; - m_localAnchorD = prismatic->m_localAnchorA; - m_localAnchorB = prismatic->m_localAnchorB; - m_referenceAngleB = prismatic->m_referenceAngle; - m_localAxisD = prismatic->m_localXAxisA; - - b2Vec2 pD = m_localAnchorD; - b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); - coordinateB = b2Dot(pB - pD, m_localAxisD); - } - - m_ratio = def->ratio; - - m_constant = coordinateA + m_ratio * coordinateB; - - m_impulse = 0.0f; -} - -void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_indexC = m_bodyC->m_islandIndex; - m_indexD = m_bodyD->m_islandIndex; - m_lcA = m_bodyA->m_sweep.localCenter; - m_lcB = m_bodyB->m_sweep.localCenter; - m_lcC = m_bodyC->m_sweep.localCenter; - m_lcD = m_bodyD->m_sweep.localCenter; - m_mA = m_bodyA->m_invMass; - m_mB = m_bodyB->m_invMass; - m_mC = m_bodyC->m_invMass; - m_mD = m_bodyD->m_invMass; - m_iA = m_bodyA->m_invI; - m_iB = m_bodyB->m_invI; - m_iC = m_bodyC->m_invI; - m_iD = m_bodyD->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Vec2 cC = data.positions[m_indexC].c; - float32 aC = data.positions[m_indexC].a; - b2Vec2 vC = data.velocities[m_indexC].v; - float32 wC = data.velocities[m_indexC].w; - - b2Vec2 cD = data.positions[m_indexD].c; - float32 aD = data.positions[m_indexD].a; - b2Vec2 vD = data.velocities[m_indexD].v; - float32 wD = data.velocities[m_indexD].w; - - b2Rot qA(aA), qB(aB), qC(aC), qD(aD); - - m_mass = 0.0f; - - if (m_typeA == e_revoluteJoint) - { - m_JvAC.SetZero(); - m_JwA = 1.0f; - m_JwC = 1.0f; - m_mass += m_iA + m_iC; - } - else - { - b2Vec2 u = b2Mul(qC, m_localAxisC); - b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); - m_JvAC = u; - m_JwC = b2Cross(rC, u); - m_JwA = b2Cross(rA, u); - m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; - } - - if (m_typeB == e_revoluteJoint) - { - m_JvBD.SetZero(); - m_JwB = m_ratio; - m_JwD = m_ratio; - m_mass += m_ratio * m_ratio * (m_iB + m_iD); - } - else - { - b2Vec2 u = b2Mul(qD, m_localAxisD); - b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); - m_JvBD = m_ratio * u; - m_JwD = m_ratio * b2Cross(rD, u); - m_JwB = m_ratio * b2Cross(rB, u); - m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; - } - - // Compute effective mass. - m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; - - if (data.step.warmStarting) - { - vA += (m_mA * m_impulse) * m_JvAC; - wA += m_iA * m_impulse * m_JwA; - vB += (m_mB * m_impulse) * m_JvBD; - wB += m_iB * m_impulse * m_JwB; - vC -= (m_mC * m_impulse) * m_JvAC; - wC -= m_iC * m_impulse * m_JwC; - vD -= (m_mD * m_impulse) * m_JvBD; - wD -= m_iD * m_impulse * m_JwD; - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; - data.velocities[m_indexC].v = vC; - data.velocities[m_indexC].w = wC; - data.velocities[m_indexD].v = vD; - data.velocities[m_indexD].w = wD; -} - -void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - b2Vec2 vC = data.velocities[m_indexC].v; - float32 wC = data.velocities[m_indexC].w; - b2Vec2 vD = data.velocities[m_indexD].v; - float32 wD = data.velocities[m_indexD].w; - - float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); - Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); - - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - vA += (m_mA * impulse) * m_JvAC; - wA += m_iA * impulse * m_JwA; - vB += (m_mB * impulse) * m_JvBD; - wB += m_iB * impulse * m_JwB; - vC -= (m_mC * impulse) * m_JvAC; - wC -= m_iC * impulse * m_JwC; - vD -= (m_mD * impulse) * m_JvBD; - wD -= m_iD * impulse * m_JwD; - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; - data.velocities[m_indexC].v = vC; - data.velocities[m_indexC].w = wC; - data.velocities[m_indexD].v = vD; - data.velocities[m_indexD].w = wD; -} - -bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 cC = data.positions[m_indexC].c; - float32 aC = data.positions[m_indexC].a; - b2Vec2 cD = data.positions[m_indexD].c; - float32 aD = data.positions[m_indexD].a; - - b2Rot qA(aA), qB(aB), qC(aC), qD(aD); - - float32 linearError = 0.0f; - - float32 coordinateA, coordinateB; - - b2Vec2 JvAC, JvBD; - float32 JwA, JwB, JwC, JwD; - float32 mass = 0.0f; - - if (m_typeA == e_revoluteJoint) - { - JvAC.SetZero(); - JwA = 1.0f; - JwC = 1.0f; - mass += m_iA + m_iC; - - coordinateA = aA - aC - m_referenceAngleA; - } - else - { - b2Vec2 u = b2Mul(qC, m_localAxisC); - b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); - JvAC = u; - JwC = b2Cross(rC, u); - JwA = b2Cross(rA, u); - mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; - - b2Vec2 pC = m_localAnchorC - m_lcC; - b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); - coordinateA = b2Dot(pA - pC, m_localAxisC); - } - - if (m_typeB == e_revoluteJoint) - { - JvBD.SetZero(); - JwB = m_ratio; - JwD = m_ratio; - mass += m_ratio * m_ratio * (m_iB + m_iD); - - coordinateB = aB - aD - m_referenceAngleB; - } - else - { - b2Vec2 u = b2Mul(qD, m_localAxisD); - b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); - JvBD = m_ratio * u; - JwD = m_ratio * b2Cross(rD, u); - JwB = m_ratio * b2Cross(rB, u); - mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; - - b2Vec2 pD = m_localAnchorD - m_lcD; - b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); - coordinateB = b2Dot(pB - pD, m_localAxisD); - } - - float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; - - float32 impulse = 0.0f; - if (mass > 0.0f) - { - impulse = -C / mass; - } - - cA += m_mA * impulse * JvAC; - aA += m_iA * impulse * JwA; - cB += m_mB * impulse * JvBD; - aB += m_iB * impulse * JwB; - cC -= m_mC * impulse * JvAC; - aC -= m_iC * impulse * JwC; - cD -= m_mD * impulse * JvBD; - aD -= m_iD * impulse * JwD; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - data.positions[m_indexC].c = cC; - data.positions[m_indexC].a = aC; - data.positions[m_indexD].c = cD; - data.positions[m_indexD].a = aD; - - // TODO_ERIN not implemented - return linearError < b2_linearSlop; -} - -b2Vec2 b2GearJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2GearJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P = m_impulse * m_JvAC; - return inv_dt * P; -} - -float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const -{ - float32 L = m_impulse * m_JwA; - return inv_dt * L; -} - -void b2GearJoint::SetRatio(float32 ratio) -{ - b2Assert(b2IsValid(ratio)); - m_ratio = ratio; -} - -float32 b2GearJoint::GetRatio() const -{ - return m_ratio; -} - -void b2GearJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - int32 index1 = m_joint1->m_index; - int32 index2 = m_joint2->m_index; - - b2Log(" b2GearJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.joint1 = joints[%d];\n", index1); - b2Log(" jd.joint2 = joints[%d];\n", index2); - b2Log(" jd.ratio = %.15lef;\n", m_ratio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2GearJoint.h b/external/Box2D/Dynamics/Joints/b2GearJoint.h deleted file mode 100644 index f926bf6ef1..0000000000 --- a/external/Box2D/Dynamics/Joints/b2GearJoint.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_GEAR_JOINT_H -#define B2_GEAR_JOINT_H - -#include - -/// Gear joint definition. This definition requires two existing -/// revolute or prismatic joints (any combination will work). -struct b2GearJointDef : public b2JointDef -{ - b2GearJointDef() - { - type = e_gearJoint; - joint1 = NULL; - joint2 = NULL; - ratio = 1.0f; - } - - /// The first revolute/prismatic joint attached to the gear joint. - b2Joint* joint1; - - /// The second revolute/prismatic joint attached to the gear joint. - b2Joint* joint2; - - /// The gear ratio. - /// @see b2GearJoint for explanation. - float32 ratio; -}; - -/// A gear joint is used to connect two joints together. Either joint -/// can be a revolute or prismatic joint. You specify a gear ratio -/// to bind the motions together: -/// coordinate1 + ratio * coordinate2 = constant -/// The ratio can be negative or positive. If one joint is a revolute joint -/// and the other joint is a prismatic joint, then the ratio will have units -/// of length or units of 1/length. -/// @warning You have to manually destroy the gear joint if joint1 or joint2 -/// is destroyed. -class b2GearJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the first joint. - b2Joint* GetJoint1() { return m_joint1; } - - /// Get the second joint. - b2Joint* GetJoint2() { return m_joint2; } - - /// Set/Get the gear ratio. - void SetRatio(float32 ratio); - float32 GetRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2GearJoint(const b2GearJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Joint* m_joint1; - b2Joint* m_joint2; - - b2JointType m_typeA; - b2JointType m_typeB; - - // Body A is connected to body C - // Body B is connected to body D - b2Body* m_bodyC; - b2Body* m_bodyD; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localAnchorC; - b2Vec2 m_localAnchorD; - - b2Vec2 m_localAxisC; - b2Vec2 m_localAxisD; - - float32 m_referenceAngleA; - float32 m_referenceAngleB; - - float32 m_constant; - float32 m_ratio; - - float32 m_impulse; - - // Solver temp - int32 m_indexA, m_indexB, m_indexC, m_indexD; - b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; - float32 m_mA, m_mB, m_mC, m_mD; - float32 m_iA, m_iB, m_iC, m_iD; - b2Vec2 m_JvAC, m_JvBD; - float32 m_JwA, m_JwB, m_JwC, m_JwD; - float32 m_mass; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2Joint.cpp b/external/Box2D/Dynamics/Joints/b2Joint.cpp deleted file mode 100644 index 6853b09f0b..0000000000 --- a/external/Box2D/Dynamics/Joints/b2Joint.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) -{ - b2Joint* joint = NULL; - - switch (def->type) - { - case e_distanceJoint: - { - void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); - joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); - } - break; - - case e_mouseJoint: - { - void* mem = allocator->Allocate(sizeof(b2MouseJoint)); - joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); - } - break; - - case e_prismaticJoint: - { - void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); - joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); - } - break; - - case e_revoluteJoint: - { - void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); - joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); - } - break; - - case e_pulleyJoint: - { - void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); - joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); - } - break; - - case e_gearJoint: - { - void* mem = allocator->Allocate(sizeof(b2GearJoint)); - joint = new (mem) b2GearJoint((b2GearJointDef*)def); - } - break; - - case e_wheelJoint: - { - void* mem = allocator->Allocate(sizeof(b2WheelJoint)); - joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); - } - break; - - case e_weldJoint: - { - void* mem = allocator->Allocate(sizeof(b2WeldJoint)); - joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); - } - break; - - case e_frictionJoint: - { - void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); - joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); - } - break; - - case e_ropeJoint: - { - void* mem = allocator->Allocate(sizeof(b2RopeJoint)); - joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); - } - break; - - default: - b2Assert(false); - break; - } - - return joint; -} - -void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) -{ - joint->~b2Joint(); - switch (joint->m_type) - { - case e_distanceJoint: - allocator->Free(joint, sizeof(b2DistanceJoint)); - break; - - case e_mouseJoint: - allocator->Free(joint, sizeof(b2MouseJoint)); - break; - - case e_prismaticJoint: - allocator->Free(joint, sizeof(b2PrismaticJoint)); - break; - - case e_revoluteJoint: - allocator->Free(joint, sizeof(b2RevoluteJoint)); - break; - - case e_pulleyJoint: - allocator->Free(joint, sizeof(b2PulleyJoint)); - break; - - case e_gearJoint: - allocator->Free(joint, sizeof(b2GearJoint)); - break; - - case e_wheelJoint: - allocator->Free(joint, sizeof(b2WheelJoint)); - break; - - case e_weldJoint: - allocator->Free(joint, sizeof(b2WeldJoint)); - break; - - case e_frictionJoint: - allocator->Free(joint, sizeof(b2FrictionJoint)); - break; - - case e_ropeJoint: - allocator->Free(joint, sizeof(b2RopeJoint)); - break; - - default: - b2Assert(false); - break; - } -} - -b2Joint::b2Joint(const b2JointDef* def) -{ - b2Assert(def->bodyA != def->bodyB); - - m_type = def->type; - m_prev = NULL; - m_next = NULL; - m_bodyA = def->bodyA; - m_bodyB = def->bodyB; - m_index = 0; - m_collideConnected = def->collideConnected; - m_islandFlag = false; - m_userData = def->userData; - - m_edgeA.joint = NULL; - m_edgeA.other = NULL; - m_edgeA.prev = NULL; - m_edgeA.next = NULL; - - m_edgeB.joint = NULL; - m_edgeB.other = NULL; - m_edgeB.prev = NULL; - m_edgeB.next = NULL; -} - -bool b2Joint::IsActive() const -{ - return m_bodyA->IsActive() && m_bodyB->IsActive(); -} diff --git a/external/Box2D/Dynamics/Joints/b2Joint.h b/external/Box2D/Dynamics/Joints/b2Joint.h deleted file mode 100644 index b4ea576665..0000000000 --- a/external/Box2D/Dynamics/Joints/b2Joint.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_JOINT_H -#define B2_JOINT_H - -#include - -class b2Body; -class b2Joint; -struct b2SolverData; -class b2BlockAllocator; - -enum b2JointType -{ - e_unknownJoint, - e_revoluteJoint, - e_prismaticJoint, - e_distanceJoint, - e_pulleyJoint, - e_mouseJoint, - e_gearJoint, - e_wheelJoint, - e_weldJoint, - e_frictionJoint, - e_ropeJoint -}; - -enum b2LimitState -{ - e_inactiveLimit, - e_atLowerLimit, - e_atUpperLimit, - e_equalLimits -}; - -struct b2Jacobian -{ - b2Vec2 linear; - float32 angularA; - float32 angularB; -}; - -/// A joint edge is used to connect bodies and joints together -/// in a joint graph where each body is a node and each joint -/// is an edge. A joint edge belongs to a doubly linked list -/// maintained in each attached body. Each joint has two joint -/// nodes, one for each attached body. -struct b2JointEdge -{ - b2Body* other; ///< provides quick access to the other body attached. - b2Joint* joint; ///< the joint - b2JointEdge* prev; ///< the previous joint edge in the body's joint list - b2JointEdge* next; ///< the next joint edge in the body's joint list -}; - -/// Joint definitions are used to construct joints. -struct b2JointDef -{ - b2JointDef() - { - type = e_unknownJoint; - userData = NULL; - bodyA = NULL; - bodyB = NULL; - collideConnected = false; - } - - /// The joint type is set automatically for concrete joint types. - b2JointType type; - - /// Use this to attach application specific data to your joints. - void* userData; - - /// The first attached body. - b2Body* bodyA; - - /// The second attached body. - b2Body* bodyB; - - /// Set this flag to true if the attached bodies should collide. - bool collideConnected; -}; - -/// The base joint class. Joints are used to constraint two bodies together in -/// various fashions. Some joints also feature limits and motors. -class b2Joint -{ -public: - - /// Get the type of the concrete joint. - b2JointType GetType() const; - - /// Get the first body attached to this joint. - b2Body* GetBodyA(); - - /// Get the second body attached to this joint. - b2Body* GetBodyB(); - - /// Get the anchor point on bodyA in world coordinates. - virtual b2Vec2 GetAnchorA() const = 0; - - /// Get the anchor point on bodyB in world coordinates. - virtual b2Vec2 GetAnchorB() const = 0; - - /// Get the reaction force on bodyB at the joint anchor in Newtons. - virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; - - /// Get the reaction torque on bodyB in N*m. - virtual float32 GetReactionTorque(float32 inv_dt) const = 0; - - /// Get the next joint the world joint list. - b2Joint* GetNext(); - const b2Joint* GetNext() const; - - /// Get the user data pointer. - void* GetUserData() const; - - /// Set the user data pointer. - void SetUserData(void* data); - - /// Short-cut function to determine if either body is inactive. - bool IsActive() const; - - /// Get collide connected. - /// Note: modifying the collide connect flag won't work correctly because - /// the flag is only checked when fixture AABBs begin to overlap. - bool GetCollideConnected() const; - - /// Dump this joint to the log file. - virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } - -protected: - friend class b2World; - friend class b2Body; - friend class b2Island; - friend class b2GearJoint; - - static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); - static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); - - b2Joint(const b2JointDef* def); - virtual ~b2Joint() {} - - virtual void InitVelocityConstraints(const b2SolverData& data) = 0; - virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; - - // This returns true if the position errors are within tolerance. - virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; - - b2JointType m_type; - b2Joint* m_prev; - b2Joint* m_next; - b2JointEdge m_edgeA; - b2JointEdge m_edgeB; - b2Body* m_bodyA; - b2Body* m_bodyB; - - int32 m_index; - - bool m_islandFlag; - bool m_collideConnected; - - void* m_userData; -}; - -inline b2JointType b2Joint::GetType() const -{ - return m_type; -} - -inline b2Body* b2Joint::GetBodyA() -{ - return m_bodyA; -} - -inline b2Body* b2Joint::GetBodyB() -{ - return m_bodyB; -} - -inline b2Joint* b2Joint::GetNext() -{ - return m_next; -} - -inline const b2Joint* b2Joint::GetNext() const -{ - return m_next; -} - -inline void* b2Joint::GetUserData() const -{ - return m_userData; -} - -inline void b2Joint::SetUserData(void* data) -{ - m_userData = data; -} - -inline bool b2Joint::GetCollideConnected() const -{ - return m_collideConnected; -} - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp deleted file mode 100644 index 237d9d519a..0000000000 --- a/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include - -// p = attached point, m = mouse point -// C = p - m -// Cdot = v -// = v + cross(w, r) -// J = [I r_skew] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) -: b2Joint(def) -{ - b2Assert(def->target.IsValid()); - b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); - b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); - b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); - - m_targetA = def->target; - m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); - - m_maxForce = def->maxForce; - m_impulse.SetZero(); - - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_beta = 0.0f; - m_gamma = 0.0f; -} - -void b2MouseJoint::SetTarget(const b2Vec2& target) -{ - if (m_bodyB->IsAwake() == false) - { - m_bodyB->SetAwake(true); - } - m_targetA = target; -} - -const b2Vec2& b2MouseJoint::GetTarget() const -{ - return m_targetA; -} - -void b2MouseJoint::SetMaxForce(float32 force) -{ - m_maxForce = force; -} - -float32 b2MouseJoint::GetMaxForce() const -{ - return m_maxForce; -} - -void b2MouseJoint::SetFrequency(float32 hz) -{ - m_frequencyHz = hz; -} - -float32 b2MouseJoint::GetFrequency() const -{ - return m_frequencyHz; -} - -void b2MouseJoint::SetDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -float32 b2MouseJoint::GetDampingRatio() const -{ - return m_dampingRatio; -} - -void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexB = m_bodyB->m_islandIndex; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassB = m_bodyB->m_invMass; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qB(aB); - - float32 mass = m_bodyB->GetMass(); - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * mass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = mass * (omega * omega); - - // magic formulas - // gamma has units of inverse mass. - // beta has units of inverse time. - float32 h = data.step.dt; - b2Assert(d + h * k > b2_epsilon); - m_gamma = h * (d + h * k); - if (m_gamma != 0.0f) - { - m_gamma = 1.0f / m_gamma; - } - m_beta = h * k * m_gamma; - - // Compute the effective mass matrix. - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] - // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] - // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] - b2Mat22 K; - K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; - K.ex.y = -m_invIB * m_rB.x * m_rB.y; - K.ey.x = K.ex.y; - K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; - - m_mass = K.GetInverse(); - - m_C = cB + m_rB - m_targetA; - m_C *= m_beta; - - // Cheat with some damping - wB *= 0.98f; - - if (data.step.warmStarting) - { - m_impulse *= data.step.dtRatio; - vB += m_invMassB * m_impulse; - wB += m_invIB * b2Cross(m_rB, m_impulse); - } - else - { - m_impulse.SetZero(); - } - - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = v + cross(w, r) - b2Vec2 Cdot = vB + b2Cross(wB, m_rB); - b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); - - b2Vec2 oldImpulse = m_impulse; - m_impulse += impulse; - float32 maxImpulse = data.step.dt * m_maxForce; - if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) - { - m_impulse *= maxImpulse / m_impulse.Length(); - } - impulse = m_impulse - oldImpulse; - - vB += m_invMassB * impulse; - wB += m_invIB * b2Cross(m_rB, impulse); - - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) -{ - B2_NOT_USED(data); - return true; -} - -b2Vec2 b2MouseJoint::GetAnchorA() const -{ - return m_targetA; -} - -b2Vec2 b2MouseJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * m_impulse; -} - -float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * 0.0f; -} diff --git a/external/Box2D/Dynamics/Joints/b2MouseJoint.h b/external/Box2D/Dynamics/Joints/b2MouseJoint.h deleted file mode 100644 index 1bbc194f4c..0000000000 --- a/external/Box2D/Dynamics/Joints/b2MouseJoint.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_MOUSE_JOINT_H -#define B2_MOUSE_JOINT_H - -#include - -/// Mouse joint definition. This requires a world target point, -/// tuning parameters, and the time step. -struct b2MouseJointDef : public b2JointDef -{ - b2MouseJointDef() - { - type = e_mouseJoint; - target.Set(0.0f, 0.0f); - maxForce = 0.0f; - frequencyHz = 5.0f; - dampingRatio = 0.7f; - } - - /// The initial world target point. This is assumed - /// to coincide with the body anchor initially. - b2Vec2 target; - - /// The maximum constraint force that can be exerted - /// to move the candidate body. Usually you will express - /// as some multiple of the weight (multiplier * mass * gravity). - float32 maxForce; - - /// The response speed. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A mouse joint is used to make a point on a body track a -/// specified world point. This a soft constraint with a maximum -/// force. This allows the constraint to stretch and without -/// applying huge forces. -/// NOTE: this joint is not documented in the manual because it was -/// developed to be used in the testbed. If you want to learn how to -/// use the mouse joint, look at the testbed. -class b2MouseJoint : public b2Joint -{ -public: - - /// Implements b2Joint. - b2Vec2 GetAnchorA() const; - - /// Implements b2Joint. - b2Vec2 GetAnchorB() const; - - /// Implements b2Joint. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Implements b2Joint. - float32 GetReactionTorque(float32 inv_dt) const; - - /// Use this to update the target point. - void SetTarget(const b2Vec2& target); - const b2Vec2& GetTarget() const; - - /// Set/get the maximum force in Newtons. - void SetMaxForce(float32 force); - float32 GetMaxForce() const; - - /// Set/get the frequency in Hertz. - void SetFrequency(float32 hz); - float32 GetFrequency() const; - - /// Set/get the damping ratio (dimensionless). - void SetDampingRatio(float32 ratio); - float32 GetDampingRatio() const; - - /// The mouse joint does not support dumping. - void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } - -protected: - friend class b2Joint; - - b2MouseJoint(const b2MouseJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_localAnchorB; - b2Vec2 m_targetA; - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_beta; - - // Solver shared - b2Vec2 m_impulse; - float32 m_maxForce; - float32 m_gamma; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rB; - b2Vec2 m_localCenterB; - float32 m_invMassB; - float32 m_invIB; - b2Mat22 m_mass; - b2Vec2 m_C; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp deleted file mode 100644 index 4849f729f5..0000000000 --- a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Linear constraint (point-to-line) -// d = p2 - p1 = x2 + r2 - x1 - r1 -// C = dot(perp, d) -// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) -// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) -// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] -// -// Angular constraint -// C = a2 - a1 + a_initial -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// -// K = J * invM * JT -// -// J = [-a -s1 a s2] -// [0 -1 0 1] -// a = perp -// s1 = cross(d + r1, a) = cross(p2 - x1, a) -// s2 = cross(r2, a) = cross(p2 - x2, a) - - -// Motor/Limit linear constraint -// C = dot(ax1, d) -// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) -// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] - -// Block Solver -// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even -// when the mass has poor distribution (leading to large torques about the joint anchor points). -// -// The Jacobian has 3 rows: -// J = [-uT -s1 uT s2] // linear -// [0 -1 0 1] // angular -// [-vT -a1 vT a2] // limit -// -// u = perp -// v = axis -// s1 = cross(d + r1, u), s2 = cross(r2, u) -// a1 = cross(d + r1, v), a2 = cross(r2, v) - -// M * (v2 - v1) = JT * df -// J * v2 = bias -// -// v2 = v1 + invM * JT * df -// J * (v1 + invM * JT * df) = bias -// K * df = bias - J * v1 = -Cdot -// K = J * invM * JT -// Cdot = J * v1 - bias -// -// Now solve for f2. -// df = f2 - f1 -// K * (f2 - f1) = -Cdot -// f2 = invK * (-Cdot) + f1 -// -// Clamp accumulated limit impulse. -// lower: f2(3) = max(f2(3), 0) -// upper: f2(3) = min(f2(3), 0) -// -// Solve for correct f2(1:2) -// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 -// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) -// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) -// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) -// -// Now compute impulse to be applied: -// df = f2 - f1 - -void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - localAxisA = bodyA->GetLocalVector(axis); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_localXAxisA = def->localAxisA; - m_localXAxisA.Normalize(); - m_localYAxisA = b2Cross(1.0f, m_localXAxisA); - m_referenceAngle = def->referenceAngle; - - m_impulse.SetZero(); - m_motorMass = 0.0; - m_motorImpulse = 0.0f; - - m_lowerTranslation = def->lowerTranslation; - m_upperTranslation = def->upperTranslation; - m_maxMotorForce = def->maxMotorForce; - m_motorSpeed = def->motorSpeed; - m_enableLimit = def->enableLimit; - m_enableMotor = def->enableMotor; - m_limitState = e_inactiveLimit; - - m_axis.SetZero(); - m_perp.SetZero(); -} - -void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective masses. - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = (cB - cA) + rB - rA; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Compute motor Jacobian and effective mass. - { - m_axis = b2Mul(qA, m_localXAxisA); - m_a1 = b2Cross(d + rA, m_axis); - m_a2 = b2Cross(rB, m_axis); - - m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - } - - // Prismatic constraint. - { - m_perp = b2Mul(qA, m_localYAxisA); - - m_s1 = b2Cross(d + rA, m_perp); - m_s2 = b2Cross(rB, m_perp); - - float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; - float32 k12 = iA * m_s1 + iB * m_s2; - float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - // For bodies with fixed rotation. - k22 = 1.0f; - } - float32 k23 = iA * m_a1 + iB * m_a2; - float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; - - m_K.ex.Set(k11, k12, k13); - m_K.ey.Set(k12, k22, k23); - m_K.ez.Set(k13, k23, k33); - } - - // Compute motor and limit terms. - if (m_enableLimit) - { - float32 jointTranslation = b2Dot(m_axis, d); - if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) - { - m_limitState = e_equalLimits; - } - else if (jointTranslation <= m_lowerTranslation) - { - if (m_limitState != e_atLowerLimit) - { - m_limitState = e_atLowerLimit; - m_impulse.z = 0.0f; - } - } - else if (jointTranslation >= m_upperTranslation) - { - if (m_limitState != e_atUpperLimit) - { - m_limitState = e_atUpperLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - - if (m_enableMotor == false) - { - m_motorImpulse = 0.0f; - } - - if (data.step.warmStarting) - { - // Account for variable time step. - m_impulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; - float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; - float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - else - { - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Solve linear motor constraint. - if (m_enableMotor && m_limitState != e_equalLimits) - { - float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; - float32 impulse = m_motorMass * (m_motorSpeed - Cdot); - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorForce; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - b2Vec2 P = impulse * m_axis; - float32 LA = impulse * m_a1; - float32 LB = impulse * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - b2Vec2 Cdot1; - Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; - Cdot1.y = wB - wA; - - if (m_enableLimit && m_limitState != e_inactiveLimit) - { - // Solve prismatic and limit constraint in block form. - float32 Cdot2; - Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 f1 = m_impulse; - b2Vec3 df = m_K.Solve33(-Cdot); - m_impulse += df; - - if (m_limitState == e_atLowerLimit) - { - m_impulse.z = b2Max(m_impulse.z, 0.0f); - } - else if (m_limitState == e_atUpperLimit) - { - m_impulse.z = b2Min(m_impulse.z, 0.0f); - } - - // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) - b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); - b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); - m_impulse.x = f2r.x; - m_impulse.y = f2r.y; - - df = m_impulse - f1; - - b2Vec2 P = df.x * m_perp + df.z * m_axis; - float32 LA = df.x * m_s1 + df.y + df.z * m_a1; - float32 LB = df.x * m_s2 + df.y + df.z * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - else - { - // Limit is inactive, just solve the prismatic constraint in block form. - b2Vec2 df = m_K.Solve22(-Cdot1); - m_impulse.x += df.x; - m_impulse.y += df.y; - - b2Vec2 P = df.x * m_perp; - float32 LA = df.x * m_s1 + df.y; - float32 LB = df.x * m_s2 + df.y; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - - b2Vec2 Cdot10 = Cdot1; - - Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; - Cdot1.y = wB - wA; - - if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f) - { - b2Vec2 test = b2Mul22(m_K, df); - Cdot1.x += 0.0f; - } - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Compute fresh Jacobians - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = cB + rB - cA - rA; - - b2Vec2 axis = b2Mul(qA, m_localXAxisA); - float32 a1 = b2Cross(d + rA, axis); - float32 a2 = b2Cross(rB, axis); - b2Vec2 perp = b2Mul(qA, m_localYAxisA); - - float32 s1 = b2Cross(d + rA, perp); - float32 s2 = b2Cross(rB, perp); - - b2Vec3 impulse; - b2Vec2 C1; - C1.x = b2Dot(perp, d); - C1.y = aB - aA - m_referenceAngle; - - float32 linearError = b2Abs(C1.x); - float32 angularError = b2Abs(C1.y); - - bool active = false; - float32 C2 = 0.0f; - if (m_enableLimit) - { - float32 translation = b2Dot(axis, d); - if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) - { - // Prevent large angular corrections - C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); - linearError = b2Max(linearError, b2Abs(translation)); - active = true; - } - else if (translation <= m_lowerTranslation) - { - // Prevent large linear corrections and allow some slop. - C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); - linearError = b2Max(linearError, m_lowerTranslation - translation); - active = true; - } - else if (translation >= m_upperTranslation) - { - // Prevent large linear corrections and allow some slop. - C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); - linearError = b2Max(linearError, translation - m_upperTranslation); - active = true; - } - } - - if (active) - { - float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; - float32 k12 = iA * s1 + iB * s2; - float32 k13 = iA * s1 * a1 + iB * s2 * a2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - // For fixed rotation - k22 = 1.0f; - } - float32 k23 = iA * a1 + iB * a2; - float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; - - b2Mat33 K; - K.ex.Set(k11, k12, k13); - K.ey.Set(k12, k22, k23); - K.ez.Set(k13, k23, k33); - - b2Vec3 C; - C.x = C1.x; - C.y = C1.y; - C.z = C2; - - impulse = K.Solve33(-C); - } - else - { - float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; - float32 k12 = iA * s1 + iB * s2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - k22 = 1.0f; - } - - b2Mat22 K; - K.ex.Set(k11, k12); - K.ey.Set(k12, k22); - - b2Vec2 impulse1 = K.Solve(-C1); - impulse.x = impulse1.x; - impulse.y = impulse1.y; - impulse.z = 0.0f; - } - - b2Vec2 P = impulse.x * perp + impulse.z * axis; - float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; - float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; - - cA -= mA * P; - aA -= iA * LA; - cB += mB * P; - aB += iB * LB; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return linearError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2PrismaticJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2PrismaticJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); -} - -float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.y; -} - -float32 b2PrismaticJoint::GetJointTranslation() const -{ - b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); - b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); - b2Vec2 d = pB - pA; - b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); - - float32 translation = b2Dot(d, axis); - return translation; -} - -float32 b2PrismaticJoint::GetJointSpeed() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - - b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); - b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); - b2Vec2 p1 = bA->m_sweep.c + rA; - b2Vec2 p2 = bB->m_sweep.c + rB; - b2Vec2 d = p2 - p1; - b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); - - b2Vec2 vA = bA->m_linearVelocity; - b2Vec2 vB = bB->m_linearVelocity; - float32 wA = bA->m_angularVelocity; - float32 wB = bB->m_angularVelocity; - - float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); - return speed; -} - -bool b2PrismaticJoint::IsLimitEnabled() const -{ - return m_enableLimit; -} - -void b2PrismaticJoint::EnableLimit(bool flag) -{ - if (flag != m_enableLimit) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableLimit = flag; - m_impulse.z = 0.0f; - } -} - -float32 b2PrismaticJoint::GetLowerLimit() const -{ - return m_lowerTranslation; -} - -float32 b2PrismaticJoint::GetUpperLimit() const -{ - return m_upperTranslation; -} - -void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) -{ - b2Assert(lower <= upper); - if (lower != m_lowerTranslation || upper != m_upperTranslation) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_lowerTranslation = lower; - m_upperTranslation = upper; - m_impulse.z = 0.0f; - } -} - -bool b2PrismaticJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2PrismaticJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -void b2PrismaticJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2PrismaticJoint::SetMaxMotorForce(float32 force) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorForce = force; -} - -float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2PrismaticJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2PrismaticJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); - b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); - b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h deleted file mode 100644 index aca2859b45..0000000000 --- a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h +++ /dev/null @@ -1,196 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_PRISMATIC_JOINT_H -#define B2_PRISMATIC_JOINT_H - -#include - -/// Prismatic joint definition. This requires defining a line of -/// motion using an axis and an anchor point. The definition uses local -/// anchor points and a local axis so that the initial configuration -/// can violate the constraint slightly. The joint translation is zero -/// when the local anchor points coincide in world space. Using local -/// anchors and a local axis helps when saving and loading a game. -struct b2PrismaticJointDef : public b2JointDef -{ - b2PrismaticJointDef() - { - type = e_prismaticJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - localAxisA.Set(1.0f, 0.0f); - referenceAngle = 0.0f; - enableLimit = false; - lowerTranslation = 0.0f; - upperTranslation = 0.0f; - enableMotor = false; - maxMotorForce = 0.0f; - motorSpeed = 0.0f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and unit world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The local translation unit axis in bodyA. - b2Vec2 localAxisA; - - /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. - float32 referenceAngle; - - /// Enable/disable the joint limit. - bool enableLimit; - - /// The lower translation limit, usually in meters. - float32 lowerTranslation; - - /// The upper translation limit, usually in meters. - float32 upperTranslation; - - /// Enable/disable the joint motor. - bool enableMotor; - - /// The maximum motor torque, usually in N-m. - float32 maxMotorForce; - - /// The desired motor speed in radians per second. - float32 motorSpeed; -}; - -/// A prismatic joint. This joint provides one degree of freedom: translation -/// along an axis fixed in bodyA. Relative rotation is prevented. You can -/// use a joint limit to restrict the range of motion and a joint motor to -/// drive the motion or to model joint friction. -class b2PrismaticJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// The local joint axis relative to bodyA. - const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Get the current joint translation, usually in meters. - float32 GetJointTranslation() const; - - /// Get the current joint translation speed, usually in meters per second. - float32 GetJointSpeed() const; - - /// Is the joint limit enabled? - bool IsLimitEnabled() const; - - /// Enable/disable the joint limit. - void EnableLimit(bool flag); - - /// Get the lower joint limit, usually in meters. - float32 GetLowerLimit() const; - - /// Get the upper joint limit, usually in meters. - float32 GetUpperLimit() const; - - /// Set the joint limits, usually in meters. - void SetLimits(float32 lower, float32 upper); - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed, usually in meters per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed, usually in meters per second. - float32 GetMotorSpeed() const; - - /// Set the maximum motor force, usually in N. - void SetMaxMotorForce(float32 force); - float32 GetMaxMotorForce() const { return m_maxMotorForce; } - - /// Get the current motor force given the inverse time step, usually in N. - float32 GetMotorForce(float32 inv_dt) const; - - /// Dump to b2Log - void Dump(); - -protected: - friend class b2Joint; - friend class b2GearJoint; - b2PrismaticJoint(const b2PrismaticJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localXAxisA; - b2Vec2 m_localYAxisA; - float32 m_referenceAngle; - b2Vec3 m_impulse; - float32 m_motorImpulse; - float32 m_lowerTranslation; - float32 m_upperTranslation; - float32 m_maxMotorForce; - float32 m_motorSpeed; - bool m_enableLimit; - bool m_enableMotor; - b2LimitState m_limitState; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Vec2 m_axis, m_perp; - float32 m_s1, m_s2; - float32 m_a1, m_a2; - b2Mat33 m_K; - float32 m_motorMass; -}; - -inline float32 b2PrismaticJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp deleted file mode 100644 index da30fae222..0000000000 --- a/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -* Copyright (c) 2007 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 -#include -#include - -// Pulley: -// length1 = norm(p1 - s1) -// length2 = norm(p2 - s2) -// C0 = (length1 + ratio * length2)_initial -// C = C0 - (length1 + ratio * length2) -// u1 = (p1 - s1) / norm(p1 - s1) -// u2 = (p2 - s2) / norm(p2 - s2) -// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) -// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] -// K = J * invM * JT -// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) - -void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, - const b2Vec2& groundA, const b2Vec2& groundB, - const b2Vec2& anchorA, const b2Vec2& anchorB, - float32 r) -{ - bodyA = bA; - bodyB = bB; - groundAnchorA = groundA; - groundAnchorB = groundB; - localAnchorA = bodyA->GetLocalPoint(anchorA); - localAnchorB = bodyB->GetLocalPoint(anchorB); - b2Vec2 dA = anchorA - groundA; - lengthA = dA.Length(); - b2Vec2 dB = anchorB - groundB; - lengthB = dB.Length(); - ratio = r; - b2Assert(ratio > b2_epsilon); -} - -b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) -: b2Joint(def) -{ - m_groundAnchorA = def->groundAnchorA; - m_groundAnchorB = def->groundAnchorB; - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_lengthA = def->lengthA; - m_lengthB = def->lengthB; - - b2Assert(def->ratio != 0.0f); - m_ratio = def->ratio; - - m_constant = def->lengthA + m_ratio * def->lengthB; - - m_impulse = 0.0f; -} - -void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // Get the pulley axes. - m_uA = cA + m_rA - m_groundAnchorA; - m_uB = cB + m_rB - m_groundAnchorB; - - float32 lengthA = m_uA.Length(); - float32 lengthB = m_uB.Length(); - - if (lengthA > 10.0f * b2_linearSlop) - { - m_uA *= 1.0f / lengthA; - } - else - { - m_uA.SetZero(); - } - - if (lengthB > 10.0f * b2_linearSlop) - { - m_uB *= 1.0f / lengthB; - } - else - { - m_uB.SetZero(); - } - - // Compute effective mass. - float32 ruA = b2Cross(m_rA, m_uA); - float32 ruB = b2Cross(m_rB, m_uB); - - float32 mA = m_invMassA + m_invIA * ruA * ruA; - float32 mB = m_invMassB + m_invIB * ruB * ruB; - - m_mass = mA + m_ratio * m_ratio * mB; - - if (m_mass > 0.0f) - { - m_mass = 1.0f / m_mass; - } - - if (data.step.warmStarting) - { - // Scale impulses to support variable time steps. - m_impulse *= data.step.dtRatio; - - // Warm starting. - b2Vec2 PA = -(m_impulse) * m_uA; - b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; - - vA += m_invMassA * PA; - wA += m_invIA * b2Cross(m_rA, PA); - vB += m_invMassB * PB; - wB += m_invIB * b2Cross(m_rB, PB); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - - float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - b2Vec2 PA = -impulse * m_uA; - b2Vec2 PB = -m_ratio * impulse * m_uB; - vA += m_invMassA * PA; - wA += m_invIA * b2Cross(m_rA, PA); - vB += m_invMassB * PB; - wB += m_invIB * b2Cross(m_rB, PB); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // Get the pulley axes. - b2Vec2 uA = cA + rA - m_groundAnchorA; - b2Vec2 uB = cB + rB - m_groundAnchorB; - - float32 lengthA = uA.Length(); - float32 lengthB = uB.Length(); - - if (lengthA > 10.0f * b2_linearSlop) - { - uA *= 1.0f / lengthA; - } - else - { - uA.SetZero(); - } - - if (lengthB > 10.0f * b2_linearSlop) - { - uB *= 1.0f / lengthB; - } - else - { - uB.SetZero(); - } - - // Compute effective mass. - float32 ruA = b2Cross(rA, uA); - float32 ruB = b2Cross(rB, uB); - - float32 mA = m_invMassA + m_invIA * ruA * ruA; - float32 mB = m_invMassB + m_invIB * ruB * ruB; - - float32 mass = mA + m_ratio * m_ratio * mB; - - if (mass > 0.0f) - { - mass = 1.0f / mass; - } - - float32 C = m_constant - lengthA - m_ratio * lengthB; - float32 linearError = b2Abs(C); - - float32 impulse = -mass * C; - - b2Vec2 PA = -impulse * uA; - b2Vec2 PB = -m_ratio * impulse * uB; - - cA += m_invMassA * PA; - aA += m_invIA * b2Cross(rA, PA); - cB += m_invMassB * PB; - aB += m_invIB * b2Cross(rB, PB); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return linearError < b2_linearSlop; -} - -b2Vec2 b2PulleyJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2PulleyJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P = m_impulse * m_uB; - return inv_dt * P; -} - -float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -b2Vec2 b2PulleyJoint::GetGroundAnchorA() const -{ - return m_groundAnchorA; -} - -b2Vec2 b2PulleyJoint::GetGroundAnchorB() const -{ - return m_groundAnchorB; -} - -float32 b2PulleyJoint::GetLengthA() const -{ - b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); - b2Vec2 s = m_groundAnchorA; - b2Vec2 d = p - s; - return d.Length(); -} - -float32 b2PulleyJoint::GetLengthB() const -{ - b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); - b2Vec2 s = m_groundAnchorB; - b2Vec2 d = p - s; - return d.Length(); -} - -float32 b2PulleyJoint::GetRatio() const -{ - return m_ratio; -} - -void b2PulleyJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2PulleyJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); - b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); - b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); - b2Log(" jd.ratio = %.15lef;\n", m_ratio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2PulleyJoint.h b/external/Box2D/Dynamics/Joints/b2PulleyJoint.h deleted file mode 100644 index 2f6df4395c..0000000000 --- a/external/Box2D/Dynamics/Joints/b2PulleyJoint.h +++ /dev/null @@ -1,143 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_PULLEY_JOINT_H -#define B2_PULLEY_JOINT_H - -#include - -const float32 b2_minPulleyLength = 2.0f; - -/// Pulley joint definition. This requires two ground anchors, -/// two dynamic body anchor points, and a pulley ratio. -struct b2PulleyJointDef : public b2JointDef -{ - b2PulleyJointDef() - { - type = e_pulleyJoint; - groundAnchorA.Set(-1.0f, 1.0f); - groundAnchorB.Set(1.0f, 1.0f); - localAnchorA.Set(-1.0f, 0.0f); - localAnchorB.Set(1.0f, 0.0f); - lengthA = 0.0f; - lengthB = 0.0f; - ratio = 1.0f; - collideConnected = true; - } - - /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. - void Initialize(b2Body* bodyA, b2Body* bodyB, - const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, - const b2Vec2& anchorA, const b2Vec2& anchorB, - float32 ratio); - - /// The first ground anchor in world coordinates. This point never moves. - b2Vec2 groundAnchorA; - - /// The second ground anchor in world coordinates. This point never moves. - b2Vec2 groundAnchorB; - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The a reference length for the segment attached to bodyA. - float32 lengthA; - - /// The a reference length for the segment attached to bodyB. - float32 lengthB; - - /// The pulley ratio, used to simulate a block-and-tackle. - float32 ratio; -}; - -/// The pulley joint is connected to two bodies and two fixed ground points. -/// The pulley supports a ratio such that: -/// length1 + ratio * length2 <= constant -/// Yes, the force transmitted is scaled by the ratio. -/// Warning: the pulley joint can get a bit squirrelly by itself. They often -/// work better when combined with prismatic joints. You should also cover the -/// the anchor points with static shapes to prevent one side from going to -/// zero length. -class b2PulleyJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the first ground anchor. - b2Vec2 GetGroundAnchorA() const; - - /// Get the second ground anchor. - b2Vec2 GetGroundAnchorB() const; - - /// Get the current length of the segment attached to bodyA. - float32 GetLengthA() const; - - /// Get the current length of the segment attached to bodyB. - float32 GetLengthB() const; - - /// Get the pulley ratio. - float32 GetRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2PulleyJoint(const b2PulleyJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_groundAnchorA; - b2Vec2 m_groundAnchorB; - float32 m_lengthA; - float32 m_lengthB; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_constant; - float32 m_ratio; - float32 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_uA; - b2Vec2 m_uB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp deleted file mode 100644 index e265d8192b..0000000000 --- a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// C = p2 - p1 -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Motor constraint -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_referenceAngle = def->referenceAngle; - - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - - m_lowerAngle = def->lowerAngle; - m_upperAngle = def->upperAngle; - m_maxMotorTorque = def->maxMotorTorque; - m_motorSpeed = def->motorSpeed; - m_enableLimit = def->enableLimit; - m_enableMotor = def->enableMotor; - m_limitState = e_inactiveLimit; -} - -void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - bool fixedRotation = (iA + iB == 0.0f); - - m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; - m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; - m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; - m_mass.ex.y = m_mass.ey.x; - m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; - m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; - m_mass.ex.z = m_mass.ez.x; - m_mass.ey.z = m_mass.ez.y; - m_mass.ez.z = iA + iB; - - m_motorMass = iA + iB; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - - if (m_enableMotor == false || fixedRotation) - { - m_motorImpulse = 0.0f; - } - - if (m_enableLimit && fixedRotation == false) - { - float32 jointAngle = aB - aA - m_referenceAngle; - if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) - { - m_limitState = e_equalLimits; - } - else if (jointAngle <= m_lowerAngle) - { - if (m_limitState != e_atLowerLimit) - { - m_impulse.z = 0.0f; - } - m_limitState = e_atLowerLimit; - } - else if (jointAngle >= m_upperAngle) - { - if (m_limitState != e_atUpperLimit) - { - m_impulse.z = 0.0f; - } - m_limitState = e_atUpperLimit; - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_impulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P(m_impulse.x, m_impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); - } - else - { - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - bool fixedRotation = (iA + iB == 0.0f); - - // Solve motor constraint. - if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) - { - float32 Cdot = wB - wA - m_motorSpeed; - float32 impulse = -m_motorMass * Cdot; - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorTorque; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve limit constraint. - if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) - { - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - float32 Cdot2 = wB - wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 impulse = -m_mass.Solve33(Cdot); - - if (m_limitState == e_equalLimits) - { - m_impulse += impulse; - } - else if (m_limitState == e_atLowerLimit) - { - float32 newImpulse = m_impulse.z + impulse.z; - if (newImpulse < 0.0f) - { - b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); - b2Vec2 reduced = m_mass.Solve22(rhs); - impulse.x = reduced.x; - impulse.y = reduced.y; - impulse.z = -m_impulse.z; - m_impulse.x += reduced.x; - m_impulse.y += reduced.y; - m_impulse.z = 0.0f; - } - else - { - m_impulse += impulse; - } - } - else if (m_limitState == e_atUpperLimit) - { - float32 newImpulse = m_impulse.z + impulse.z; - if (newImpulse > 0.0f) - { - b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); - b2Vec2 reduced = m_mass.Solve22(rhs); - impulse.x = reduced.x; - impulse.y = reduced.y; - impulse.z = -m_impulse.z; - m_impulse.x += reduced.x; - m_impulse.y += reduced.y; - m_impulse.z = 0.0f; - } - else - { - m_impulse += impulse; - } - } - - b2Vec2 P(impulse.x, impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + impulse.z); - } - else - { - // Solve point-to-point constraint - b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - b2Vec2 impulse = m_mass.Solve22(-Cdot); - - m_impulse.x += impulse.x; - m_impulse.y += impulse.y; - - vA -= mA * impulse; - wA -= iA * b2Cross(m_rA, impulse); - - vB += mB * impulse; - wB += iB * b2Cross(m_rB, impulse); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 angularError = 0.0f; - float32 positionError = 0.0f; - - bool fixedRotation = (m_invIA + m_invIB == 0.0f); - - // Solve angular limit constraint. - if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) - { - float32 angle = aB - aA - m_referenceAngle; - float32 limitImpulse = 0.0f; - - if (m_limitState == e_equalLimits) - { - // Prevent large angular corrections - float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); - limitImpulse = -m_motorMass * C; - angularError = b2Abs(C); - } - else if (m_limitState == e_atLowerLimit) - { - float32 C = angle - m_lowerAngle; - angularError = -C; - - // Prevent large angular corrections and allow some slop. - C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); - limitImpulse = -m_motorMass * C; - } - else if (m_limitState == e_atUpperLimit) - { - float32 C = angle - m_upperAngle; - angularError = C; - - // Prevent large angular corrections and allow some slop. - C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); - limitImpulse = -m_motorMass * C; - } - - aA -= m_invIA * limitImpulse; - aB += m_invIB * limitImpulse; - } - - // Solve point-to-point constraint. - { - qA.Set(aA); - qB.Set(aB); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - b2Vec2 C = cB + rB - cA - rA; - positionError = C.Length(); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat22 K; - K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; - K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; - K.ey.x = K.ex.y; - K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; - - b2Vec2 impulse = -K.Solve(C); - - cA -= mA * impulse; - aA -= iA * b2Cross(rA, impulse); - - cB += mB * impulse; - aB += iB * b2Cross(rB, impulse); - } - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return positionError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2RevoluteJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2RevoluteJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P(m_impulse.x, m_impulse.y); - return inv_dt * P; -} - -float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.z; -} - -float32 b2RevoluteJoint::GetJointAngle() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; -} - -float32 b2RevoluteJoint::GetJointSpeed() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - return bB->m_angularVelocity - bA->m_angularVelocity; -} - -bool b2RevoluteJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2RevoluteJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2RevoluteJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorTorque = torque; -} - -bool b2RevoluteJoint::IsLimitEnabled() const -{ - return m_enableLimit; -} - -void b2RevoluteJoint::EnableLimit(bool flag) -{ - if (flag != m_enableLimit) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableLimit = flag; - m_impulse.z = 0.0f; - } -} - -float32 b2RevoluteJoint::GetLowerLimit() const -{ - return m_lowerAngle; -} - -float32 b2RevoluteJoint::GetUpperLimit() const -{ - return m_upperAngle; -} - -void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) -{ - b2Assert(lower <= upper); - - if (lower != m_lowerAngle || upper != m_upperAngle) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_impulse.z = 0.0f; - m_lowerAngle = lower; - m_upperAngle = upper; - } -} - -void b2RevoluteJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2RevoluteJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); - b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); - b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h deleted file mode 100644 index 978f16259a..0000000000 --- a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h +++ /dev/null @@ -1,204 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_REVOLUTE_JOINT_H -#define B2_REVOLUTE_JOINT_H - -#include - -/// Revolute joint definition. This requires defining an -/// anchor point where the bodies are joined. The definition -/// uses local anchor points so that the initial configuration -/// can violate the constraint slightly. You also need to -/// specify the initial relative angle for joint limits. This -/// helps when saving and loading a game. -/// The local anchor points are measured from the body's origin -/// rather than the center of mass because: -/// 1. you might not know where the center of mass will be. -/// 2. if you add/remove shapes from a body and recompute the mass, -/// the joints will be broken. -struct b2RevoluteJointDef : public b2JointDef -{ - b2RevoluteJointDef() - { - type = e_revoluteJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - referenceAngle = 0.0f; - lowerAngle = 0.0f; - upperAngle = 0.0f; - maxMotorTorque = 0.0f; - motorSpeed = 0.0f; - enableLimit = false; - enableMotor = false; - } - - /// Initialize the bodies, anchors, and reference angle using a world - /// anchor point. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The bodyB angle minus bodyA angle in the reference state (radians). - float32 referenceAngle; - - /// A flag to enable joint limits. - bool enableLimit; - - /// The lower angle for the joint limit (radians). - float32 lowerAngle; - - /// The upper angle for the joint limit (radians). - float32 upperAngle; - - /// A flag to enable the joint motor. - bool enableMotor; - - /// The desired motor speed. Usually in radians per second. - float32 motorSpeed; - - /// The maximum motor torque used to achieve the desired motor speed. - /// Usually in N-m. - float32 maxMotorTorque; -}; - -/// A revolute joint constrains two bodies to share a common point while they -/// are free to rotate about the point. The relative rotation about the shared -/// point is the joint angle. You can limit the relative rotation with -/// a joint limit that specifies a lower and upper angle. You can use a motor -/// to drive the relative rotation about the shared point. A maximum motor torque -/// is provided so that infinite forces are not generated. -class b2RevoluteJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Get the current joint angle in radians. - float32 GetJointAngle() const; - - /// Get the current joint angle speed in radians per second. - float32 GetJointSpeed() const; - - /// Is the joint limit enabled? - bool IsLimitEnabled() const; - - /// Enable/disable the joint limit. - void EnableLimit(bool flag); - - /// Get the lower joint limit in radians. - float32 GetLowerLimit() const; - - /// Get the upper joint limit in radians. - float32 GetUpperLimit() const; - - /// Set the joint limits in radians. - void SetLimits(float32 lower, float32 upper); - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed in radians per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed in radians per second. - float32 GetMotorSpeed() const; - - /// Set the maximum motor torque, usually in N-m. - void SetMaxMotorTorque(float32 torque); - float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } - - /// Get the reaction force given the inverse time step. - /// Unit is N. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Get the reaction torque due to the joint limit given the inverse time step. - /// Unit is N*m. - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the current motor torque given the inverse time step. - /// Unit is N*m. - float32 GetMotorTorque(float32 inv_dt) const; - - /// Dump to b2Log. - void Dump(); - -protected: - - friend class b2Joint; - friend class b2GearJoint; - - b2RevoluteJoint(const b2RevoluteJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec3 m_impulse; - float32 m_motorImpulse; - - bool m_enableMotor; - float32 m_maxMotorTorque; - float32 m_motorSpeed; - - bool m_enableLimit; - float32 m_referenceAngle; - float32 m_lowerAngle; - float32 m_upperAngle; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat33 m_mass; // effective mass for point-to-point constraint. - float32 m_motorMass; // effective mass for motor/limit angular constraint. - b2LimitState m_limitState; -}; - -inline float32 b2RevoluteJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp deleted file mode 100644 index 17a70d9230..0000000000 --- a/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* -* Copyright (c) 2007-2011 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 -#include -#include - - -// Limit: -// C = norm(pB - pA) - L -// u = (pB - pA) / norm(pB - pA) -// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) -// J = [-u -cross(rA, u) u cross(rB, u)] -// K = J * invM * JT -// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 - -b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_maxLength = def->maxLength; - - m_mass = 0.0f; - m_impulse = 0.0f; - m_state = e_inactiveLimit; - m_length = 0.0f; -} - -void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - m_u = cB + m_rB - cA - m_rA; - - m_length = m_u.Length(); - - float32 C = m_length - m_maxLength; - if (C > 0.0f) - { - m_state = e_atUpperLimit; - } - else - { - m_state = e_inactiveLimit; - } - - if (m_length > b2_linearSlop) - { - m_u *= 1.0f / m_length; - } - else - { - m_u.SetZero(); - m_mass = 0.0f; - m_impulse = 0.0f; - return; - } - - // Compute effective mass. - float32 crA = b2Cross(m_rA, m_u); - float32 crB = b2Cross(m_rB, m_u); - float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; - - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - - if (data.step.warmStarting) - { - // Scale the impulse to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = dot(u, v + cross(w, r)) - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - float32 C = m_length - m_maxLength; - float32 Cdot = b2Dot(m_u, vpB - vpA); - - // Predictive constraint. - if (C < 0.0f) - { - Cdot += data.step.inv_dt * C; - } - - float32 impulse = -m_mass * Cdot; - float32 oldImpulse = m_impulse; - m_impulse = b2Min(0.0f, m_impulse + impulse); - impulse = m_impulse - oldImpulse; - - b2Vec2 P = impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 u = cB + rB - cA - rA; - - float32 length = u.Normalize(); - float32 C = length - m_maxLength; - - C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); - - float32 impulse = -m_mass * C; - b2Vec2 P = impulse * u; - - cA -= m_invMassA * P; - aA -= m_invIA * b2Cross(rA, P); - cB += m_invMassB * P; - aB += m_invIB * b2Cross(rB, P); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return length - m_maxLength < b2_linearSlop; -} - -b2Vec2 b2RopeJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2RopeJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 F = (inv_dt * m_impulse) * m_u; - return F; -} - -float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -float32 b2RopeJoint::GetMaxLength() const -{ - return m_maxLength; -} - -b2LimitState b2RopeJoint::GetLimitState() const -{ - return m_state; -} - -void b2RopeJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2RopeJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2RopeJoint.h b/external/Box2D/Dynamics/Joints/b2RopeJoint.h deleted file mode 100644 index d7091b6650..0000000000 --- a/external/Box2D/Dynamics/Joints/b2RopeJoint.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_ROPE_JOINT_H -#define B2_ROPE_JOINT_H - -#include - -/// Rope joint definition. This requires two body anchor points and -/// a maximum lengths. -/// Note: by default the connected objects will not collide. -/// see collideConnected in b2JointDef. -struct b2RopeJointDef : public b2JointDef -{ - b2RopeJointDef() - { - type = e_ropeJoint; - localAnchorA.Set(-1.0f, 0.0f); - localAnchorB.Set(1.0f, 0.0f); - maxLength = 0.0f; - } - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The maximum length of the rope. - /// Warning: this must be larger than b2_linearSlop or - /// the joint will have no effect. - float32 maxLength; -}; - -/// A rope joint enforces a maximum distance between two points -/// on two bodies. It has no other effect. -/// Warning: if you attempt to change the maximum length during -/// the simulation you will get some non-physical behavior. -/// A model that would allow you to dynamically modify the length -/// would have some sponginess, so I chose not to implement it -/// that way. See b2DistanceJoint if you want to dynamically -/// control length. -class b2RopeJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set/Get the maximum length of the rope. - void SetMaxLength(float32 length) { m_maxLength = length; } - float32 GetMaxLength() const; - - b2LimitState GetLimitState() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2RopeJoint(const b2RopeJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_maxLength; - float32 m_length; - float32 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_u; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; - b2LimitState m_state; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp deleted file mode 100644 index f50bdd6587..0000000000 --- a/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// C = p2 - p1 -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Angle constraint -// C = angle2 - angle1 - referenceAngle -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_referenceAngle = def->referenceAngle; - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_impulse.SetZero(); -} - -void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat33 K; - K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; - K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; - K.ez.x = -m_rA.y * iA - m_rB.y * iB; - K.ex.y = K.ey.x; - K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; - K.ez.y = m_rA.x * iA + m_rB.x * iB; - K.ex.z = K.ez.x; - K.ey.z = K.ez.y; - K.ez.z = iA + iB; - - if (m_frequencyHz > 0.0f) - { - K.GetInverse22(&m_mass); - - float32 invM = iA + iB; - float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; - - float32 C = aB - aA - m_referenceAngle; - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; - m_bias = C * h * k * m_gamma; - - invM += m_gamma; - m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; - } - else - { - K.GetSymInverse33(&m_mass); - m_gamma = 0.0f; - m_bias = 0.0f; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P(m_impulse.x, m_impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_impulse.z); - } - else - { - m_impulse.SetZero(); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - if (m_frequencyHz > 0.0f) - { - float32 Cdot2 = wB - wA; - - float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); - m_impulse.z += impulse2; - - wA -= iA * impulse2; - wB += iB * impulse2; - - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - - b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); - m_impulse.x += impulse1.x; - m_impulse.y += impulse1.y; - - b2Vec2 P = impulse1; - - vA -= mA * P; - wA -= iA * b2Cross(m_rA, P); - - vB += mB * P; - wB += iB * b2Cross(m_rB, P); - } - else - { - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - float32 Cdot2 = wB - wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 impulse = -b2Mul(m_mass, Cdot); - m_impulse += impulse; - - b2Vec2 P(impulse.x, impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + impulse.z); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - float32 positionError, angularError; - - b2Mat33 K; - K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; - K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; - K.ez.x = -rA.y * iA - rB.y * iB; - K.ex.y = K.ey.x; - K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; - K.ez.y = rA.x * iA + rB.x * iB; - K.ex.z = K.ez.x; - K.ey.z = K.ez.y; - K.ez.z = iA + iB; - - if (m_frequencyHz > 0.0f) - { - b2Vec2 C1 = cB + rB - cA - rA; - - positionError = C1.Length(); - angularError = 0.0f; - - b2Vec2 P = -K.Solve22(C1); - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - else - { - b2Vec2 C1 = cB + rB - cA - rA; - float32 C2 = aB - aA - m_referenceAngle; - - positionError = C1.Length(); - angularError = b2Abs(C2); - - b2Vec3 C(C1.x, C1.y, C2); - - b2Vec3 impulse = -K.Solve33(C); - b2Vec2 P(impulse.x, impulse.y); - - cA -= mA * P; - aA -= iA * (b2Cross(rA, P) + impulse.z); - - cB += mB * P; - aB += iB * (b2Cross(rB, P) + impulse.z); - } - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return positionError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2WeldJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2WeldJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P(m_impulse.x, m_impulse.y); - return inv_dt * P; -} - -float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.z; -} - -void b2WeldJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2WeldJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2WeldJoint.h b/external/Box2D/Dynamics/Joints/b2WeldJoint.h deleted file mode 100644 index 751c6a8770..0000000000 --- a/external/Box2D/Dynamics/Joints/b2WeldJoint.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WELD_JOINT_H -#define B2_WELD_JOINT_H - -#include - -/// Weld joint definition. You need to specify local anchor points -/// where they are attached and the relative body angle. The position -/// of the anchor points is important for computing the reaction torque. -struct b2WeldJointDef : public b2JointDef -{ - b2WeldJointDef() - { - type = e_weldJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - referenceAngle = 0.0f; - frequencyHz = 0.0f; - dampingRatio = 0.0f; - } - - /// Initialize the bodies, anchors, and reference angle using a world - /// anchor point. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The bodyB angle minus bodyA angle in the reference state (radians). - float32 referenceAngle; - - /// The mass-spring-damper frequency in Hertz. Rotation only. - /// Disable softness with a value of 0. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A weld joint essentially glues two bodies together. A weld joint may -/// distort somewhat because the island constraint solver is approximate. -class b2WeldJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Set/get frequency in Hz. - void SetFrequency(float32 hz) { m_frequencyHz = hz; } - float32 GetFrequency() const { return m_frequencyHz; } - - /// Set/get damping ratio. - void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } - float32 GetDampingRatio() const { return m_dampingRatio; } - - /// Dump to b2Log - void Dump(); - -protected: - - friend class b2Joint; - - b2WeldJoint(const b2WeldJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_bias; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_referenceAngle; - float32 m_gamma; - b2Vec3 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat33 m_mass; -}; - -#endif diff --git a/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp deleted file mode 100644 index 6253437706..0000000000 --- a/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include - -// Linear constraint (point-to-line) -// d = pB - pA = xB + rB - xA - rA -// C = dot(ay, d) -// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) -// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) -// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] - -// Spring linear constraint -// C = dot(ax, d) -// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) -// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] - -// Motor rotational constraint -// Cdot = wB - wA -// J = [0 0 -1 0 0 1] - -void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - localAxisA = bodyA->GetLocalVector(axis); -} - -b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_localXAxisA = def->localAxisA; - m_localYAxisA = b2Cross(1.0f, m_localXAxisA); - - m_mass = 0.0f; - m_impulse = 0.0f; - m_motorMass = 0.0; - m_motorImpulse = 0.0f; - m_springMass = 0.0f; - m_springImpulse = 0.0f; - - m_maxMotorTorque = def->maxMotorTorque; - m_motorSpeed = def->motorSpeed; - m_enableMotor = def->enableMotor; - - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_bias = 0.0f; - m_gamma = 0.0f; - - m_ax.SetZero(); - m_ay.SetZero(); -} - -void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective masses. - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = cB + rB - cA - rA; - - // Point to line constraint - { - m_ay = b2Mul(qA, m_localYAxisA); - m_sAy = b2Cross(d + rA, m_ay); - m_sBy = b2Cross(rB, m_ay); - - m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; - - if (m_mass > 0.0f) - { - m_mass = 1.0f / m_mass; - } - } - - // Spring constraint - m_springMass = 0.0f; - m_bias = 0.0f; - m_gamma = 0.0f; - if (m_frequencyHz > 0.0f) - { - m_ax = b2Mul(qA, m_localXAxisA); - m_sAx = b2Cross(d + rA, m_ax); - m_sBx = b2Cross(rB, m_ax); - - float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; - - if (invMass > 0.0f) - { - m_springMass = 1.0f / invMass; - - float32 C = b2Dot(d, m_ax); - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m_springMass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m_springMass * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - if (m_gamma > 0.0f) - { - m_gamma = 1.0f / m_gamma; - } - - m_bias = C * h * k * m_gamma; - - m_springMass = invMass + m_gamma; - if (m_springMass > 0.0f) - { - m_springMass = 1.0f / m_springMass; - } - } - } - else - { - m_springImpulse = 0.0f; - } - - // Rotational motor - if (m_enableMotor) - { - m_motorMass = iA + iB; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - } - else - { - m_motorMass = 0.0f; - m_motorImpulse = 0.0f; - } - - if (data.step.warmStarting) - { - // Account for variable time step. - m_impulse *= data.step.dtRatio; - m_springImpulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; - float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; - float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; - - vA -= m_invMassA * P; - wA -= m_invIA * LA; - - vB += m_invMassB * P; - wB += m_invIB * LB; - } - else - { - m_impulse = 0.0f; - m_springImpulse = 0.0f; - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Solve spring constraint - { - float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; - float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); - m_springImpulse += impulse; - - b2Vec2 P = impulse * m_ax; - float32 LA = impulse * m_sAx; - float32 LB = impulse * m_sBx; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - // Solve rotational motor constraint - { - float32 Cdot = wB - wA - m_motorSpeed; - float32 impulse = -m_motorMass * Cdot; - - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorTorque; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve point to line constraint - { - float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - b2Vec2 P = impulse * m_ay; - float32 LA = impulse * m_sAy; - float32 LB = impulse * m_sBy; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = (cB - cA) + rB - rA; - - b2Vec2 ay = b2Mul(qA, m_localYAxisA); - - float32 sAy = b2Cross(d + rA, ay); - float32 sBy = b2Cross(rB, ay); - - float32 C = b2Dot(d, ay); - - float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; - - float32 impulse; - if (k != 0.0f) - { - impulse = - C / k; - } - else - { - impulse = 0.0f; - } - - b2Vec2 P = impulse * ay; - float32 LA = impulse * sAy; - float32 LB = impulse * sBy; - - cA -= m_invMassA * P; - aA -= m_invIA * LA; - cB += m_invMassB * P; - aB += m_invIB * LB; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return b2Abs(C) <= b2_linearSlop; -} - -b2Vec2 b2WheelJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2WheelJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); -} - -float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -float32 b2WheelJoint::GetJointTranslation() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - - b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); - b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); - b2Vec2 d = pB - pA; - b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); - - float32 translation = b2Dot(d, axis); - return translation; -} - -float32 b2WheelJoint::GetJointSpeed() const -{ - float32 wA = m_bodyA->m_angularVelocity; - float32 wB = m_bodyB->m_angularVelocity; - return wB - wA; -} - -bool b2WheelJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2WheelJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -void b2WheelJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2WheelJoint::SetMaxMotorTorque(float32 torque) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorTorque = torque; -} - -float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2WheelJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2WheelJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/Box2D/Dynamics/Joints/b2WheelJoint.h b/external/Box2D/Dynamics/Joints/b2WheelJoint.h deleted file mode 100644 index ede1b08b7c..0000000000 --- a/external/Box2D/Dynamics/Joints/b2WheelJoint.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WHEEL_JOINT_H -#define B2_WHEEL_JOINT_H - -#include - -/// Wheel joint definition. This requires defining a line of -/// motion using an axis and an anchor point. The definition uses local -/// anchor points and a local axis so that the initial configuration -/// can violate the constraint slightly. The joint translation is zero -/// when the local anchor points coincide in world space. Using local -/// anchors and a local axis helps when saving and loading a game. -struct b2WheelJointDef : public b2JointDef -{ - b2WheelJointDef() - { - type = e_wheelJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - localAxisA.Set(1.0f, 0.0f); - enableMotor = false; - maxMotorTorque = 0.0f; - motorSpeed = 0.0f; - frequencyHz = 2.0f; - dampingRatio = 0.7f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The local translation axis in bodyA. - b2Vec2 localAxisA; - - /// Enable/disable the joint motor. - bool enableMotor; - - /// The maximum motor torque, usually in N-m. - float32 maxMotorTorque; - - /// The desired motor speed in radians per second. - float32 motorSpeed; - - /// Suspension frequency, zero indicates no suspension - float32 frequencyHz; - - /// Suspension damping ratio, one indicates critical damping - float32 dampingRatio; -}; - -/// A wheel joint. This joint provides two degrees of freedom: translation -/// along an axis fixed in bodyA and rotation in the plane. You can use a -/// joint limit to restrict the range of motion and a joint motor to drive -/// the rotation or to model rotational friction. -/// This joint is designed for vehicle suspensions. -class b2WheelJoint : public b2Joint -{ -public: - void GetDefinition(b2WheelJointDef* def) const; - - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// The local joint axis relative to bodyA. - const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } - - /// Get the current joint translation, usually in meters. - float32 GetJointTranslation() const; - - /// Get the current joint translation speed, usually in meters per second. - float32 GetJointSpeed() const; - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed, usually in radians per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed, usually in radians per second. - float32 GetMotorSpeed() const; - - /// Set/Get the maximum motor force, usually in N-m. - void SetMaxMotorTorque(float32 torque); - float32 GetMaxMotorTorque() const; - - /// Get the current motor torque given the inverse time step, usually in N-m. - float32 GetMotorTorque(float32 inv_dt) const; - - /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. - void SetSpringFrequencyHz(float32 hz); - float32 GetSpringFrequencyHz() const; - - /// Set/Get the spring damping ratio - void SetSpringDampingRatio(float32 ratio); - float32 GetSpringDampingRatio() const; - - /// Dump to b2Log - void Dump(); - -protected: - - friend class b2Joint; - b2WheelJoint(const b2WheelJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localXAxisA; - b2Vec2 m_localYAxisA; - - float32 m_impulse; - float32 m_motorImpulse; - float32 m_springImpulse; - - float32 m_maxMotorTorque; - float32 m_motorSpeed; - bool m_enableMotor; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - - b2Vec2 m_ax, m_ay; - float32 m_sAx, m_sBx; - float32 m_sAy, m_sBy; - - float32 m_mass; - float32 m_motorMass; - float32 m_springMass; - - float32 m_bias; - float32 m_gamma; -}; - -inline float32 b2WheelJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -inline float32 b2WheelJoint::GetMaxMotorTorque() const -{ - return m_maxMotorTorque; -} - -inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) -{ - m_frequencyHz = hz; -} - -inline float32 b2WheelJoint::GetSpringFrequencyHz() const -{ - return m_frequencyHz; -} - -inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -inline float32 b2WheelJoint::GetSpringDampingRatio() const -{ - return m_dampingRatio; -} - -#endif diff --git a/external/Box2D/Dynamics/b2Body.cpp b/external/Box2D/Dynamics/b2Body.cpp deleted file mode 100644 index b22b574023..0000000000 --- a/external/Box2D/Dynamics/b2Body.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include -#include -#include - -b2Body::b2Body(const b2BodyDef* bd, b2World* world) -{ - b2Assert(bd->position.IsValid()); - b2Assert(bd->linearVelocity.IsValid()); - b2Assert(b2IsValid(bd->angle)); - b2Assert(b2IsValid(bd->angularVelocity)); - b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); - b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); - - m_flags = 0; - - if (bd->bullet) - { - m_flags |= e_bulletFlag; - } - if (bd->fixedRotation) - { - m_flags |= e_fixedRotationFlag; - } - if (bd->allowSleep) - { - m_flags |= e_autoSleepFlag; - } - if (bd->awake) - { - m_flags |= e_awakeFlag; - } - if (bd->active) - { - m_flags |= e_activeFlag; - } - - m_world = world; - - m_xf.p = bd->position; - m_xf.q.Set(bd->angle); - - m_sweep.localCenter.SetZero(); - m_sweep.c0 = m_xf.p; - m_sweep.c = m_xf.p; - m_sweep.a0 = bd->angle; - m_sweep.a = bd->angle; - m_sweep.alpha0 = 0.0f; - - m_jointList = NULL; - m_contactList = NULL; - m_prev = NULL; - m_next = NULL; - - m_linearVelocity = bd->linearVelocity; - m_angularVelocity = bd->angularVelocity; - - m_linearDamping = bd->linearDamping; - m_angularDamping = bd->angularDamping; - m_gravityScale = bd->gravityScale; - - m_force.SetZero(); - m_torque = 0.0f; - - m_sleepTime = 0.0f; - - m_type = bd->type; - - if (m_type == b2_dynamicBody) - { - m_mass = 1.0f; - m_invMass = 1.0f; - } - else - { - m_mass = 0.0f; - m_invMass = 0.0f; - } - - m_I = 0.0f; - m_invI = 0.0f; - - m_userData = bd->userData; - - m_fixtureList = NULL; - m_fixtureCount = 0; -} - -b2Body::~b2Body() -{ - // shapes and joints are destroyed in b2World::Destroy -} - -void b2Body::SetType(b2BodyType type) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - if (m_type == type) - { - return; - } - - m_type = type; - - ResetMassData(); - - if (m_type == b2_staticBody) - { - m_linearVelocity.SetZero(); - m_angularVelocity = 0.0f; - m_sweep.a0 = m_sweep.a; - m_sweep.c0 = m_sweep.c; - SynchronizeFixtures(); - } - - SetAwake(true); - - m_force.SetZero(); - m_torque = 0.0f; - - // Since the body type changed, we need to flag contacts for filtering. - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Refilter(); - } -} - -b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return NULL; - } - - b2BlockAllocator* allocator = &m_world->m_blockAllocator; - - void* memory = allocator->Allocate(sizeof(b2Fixture)); - b2Fixture* fixture = new (memory) b2Fixture; - fixture->Create(allocator, this, def); - - if (m_flags & e_activeFlag) - { - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - fixture->CreateProxies(broadPhase, m_xf); - } - - fixture->m_next = m_fixtureList; - m_fixtureList = fixture; - ++m_fixtureCount; - - fixture->m_body = this; - - // Adjust mass properties if needed. - if (fixture->m_density > 0.0f) - { - ResetMassData(); - } - - // Let the world know we have a new fixture. This will cause new contacts - // to be created at the beginning of the next time step. - m_world->m_flags |= b2World::e_newFixture; - - return fixture; -} - -b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) -{ - b2FixtureDef def; - def.shape = shape; - def.density = density; - - return CreateFixture(&def); -} - -void b2Body::DestroyFixture(b2Fixture* fixture) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - b2Assert(fixture->m_body == this); - - // Remove the fixture from this body's singly linked list. - b2Assert(m_fixtureCount > 0); - b2Fixture** node = &m_fixtureList; - bool found = false; - while (*node != NULL) - { - if (*node == fixture) - { - *node = fixture->m_next; - found = true; - break; - } - - node = &(*node)->m_next; - } - - // You tried to remove a shape that is not attached to this body. - b2Assert(found); - - // Destroy any contacts associated with the fixture. - b2ContactEdge* edge = m_contactList; - while (edge) - { - b2Contact* c = edge->contact; - edge = edge->next; - - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - - if (fixture == fixtureA || fixture == fixtureB) - { - // This destroys the contact and removes it from - // this body's contact list. - m_world->m_contactManager.Destroy(c); - } - } - - b2BlockAllocator* allocator = &m_world->m_blockAllocator; - - if (m_flags & e_activeFlag) - { - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - fixture->DestroyProxies(broadPhase); - } - - fixture->Destroy(allocator); - fixture->m_body = NULL; - fixture->m_next = NULL; - fixture->~b2Fixture(); - allocator->Free(fixture, sizeof(b2Fixture)); - - --m_fixtureCount; - - // Reset the mass data. - ResetMassData(); -} - -void b2Body::ResetMassData() -{ - // Compute mass data from shapes. Each shape has its own density. - m_mass = 0.0f; - m_invMass = 0.0f; - m_I = 0.0f; - m_invI = 0.0f; - m_sweep.localCenter.SetZero(); - - // Static and kinematic bodies have zero mass. - if (m_type == b2_staticBody || m_type == b2_kinematicBody) - { - m_sweep.c0 = m_xf.p; - m_sweep.c = m_xf.p; - m_sweep.a0 = m_sweep.a; - return; - } - - b2Assert(m_type == b2_dynamicBody); - - // Accumulate mass over all fixtures. - b2Vec2 localCenter = b2Vec2_zero; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - if (f->m_density == 0.0f) - { - continue; - } - - b2MassData massData; - f->GetMassData(&massData); - m_mass += massData.mass; - localCenter += massData.mass * massData.center; - m_I += massData.I; - } - - // Compute center of mass. - if (m_mass > 0.0f) - { - m_invMass = 1.0f / m_mass; - localCenter *= m_invMass; - } - else - { - // Force all dynamic bodies to have a positive mass. - m_mass = 1.0f; - m_invMass = 1.0f; - } - - if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) - { - // Center the inertia about the center of mass. - m_I -= m_mass * b2Dot(localCenter, localCenter); - b2Assert(m_I > 0.0f); - m_invI = 1.0f / m_I; - - } - else - { - m_I = 0.0f; - m_invI = 0.0f; - } - - // Move center of mass. - b2Vec2 oldCenter = m_sweep.c; - m_sweep.localCenter = localCenter; - m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - - // Update center of mass velocity. - m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); -} - -void b2Body::SetMassData(const b2MassData* massData) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - if (m_type != b2_dynamicBody) - { - return; - } - - m_invMass = 0.0f; - m_I = 0.0f; - m_invI = 0.0f; - - m_mass = massData->mass; - if (m_mass <= 0.0f) - { - m_mass = 1.0f; - } - - m_invMass = 1.0f / m_mass; - - if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) - { - m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); - b2Assert(m_I > 0.0f); - m_invI = 1.0f / m_I; - } - - // Move center of mass. - b2Vec2 oldCenter = m_sweep.c; - m_sweep.localCenter = massData->center; - m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - - // Update center of mass velocity. - m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); -} - -bool b2Body::ShouldCollide(const b2Body* other) const -{ - // At least one body should be dynamic. - if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) - { - return false; - } - - // Does a joint prevent collision? - for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) - { - if (jn->other == other) - { - if (jn->joint->m_collideConnected == false) - { - return false; - } - } - } - - return true; -} - -void b2Body::SetTransform(const b2Vec2& position, float32 angle) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - m_xf.q.Set(angle); - m_xf.p = position; - - m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - m_sweep.a = angle; - - m_sweep.c0 = m_sweep.c; - m_sweep.a0 = angle; - - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Synchronize(broadPhase, m_xf, m_xf); - } - - m_world->m_contactManager.FindNewContacts(); -} - -void b2Body::SynchronizeFixtures() -{ - b2Transform xf1; - xf1.q.Set(m_sweep.a0); - xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); - - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Synchronize(broadPhase, xf1, m_xf); - } -} - -void b2Body::SetActive(bool flag) -{ - b2Assert(m_world->IsLocked() == false); - - if (flag == IsActive()) - { - return; - } - - if (flag) - { - m_flags |= e_activeFlag; - - // Create all proxies. - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->CreateProxies(broadPhase, m_xf); - } - - // Contacts are created the next time step. - } - else - { - m_flags &= ~e_activeFlag; - - // Destroy all proxies. - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->DestroyProxies(broadPhase); - } - - // Destroy the attached contacts. - b2ContactEdge* ce = m_contactList; - while (ce) - { - b2ContactEdge* ce0 = ce; - ce = ce->next; - m_world->m_contactManager.Destroy(ce0->contact); - } - m_contactList = NULL; - } -} - -void b2Body::Dump() -{ - int32 bodyIndex = m_islandIndex; - - b2Log("{\n"); - b2Log(" b2BodyDef bd;\n"); - b2Log(" bd.type = b2BodyType(%d);\n", m_type); - b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); - b2Log(" bd.angle = %.15lef;\n", m_sweep.a); - b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); - b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); - b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); - b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); - b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); - b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); - b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); - b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); - b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); - b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); - b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); - b2Log("\n"); - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - b2Log(" {\n"); - f->Dump(bodyIndex); - b2Log(" }\n"); - } - b2Log("}\n"); -} \ No newline at end of file diff --git a/external/Box2D/Dynamics/b2Body.h b/external/Box2D/Dynamics/b2Body.h deleted file mode 100644 index e2d16bf630..0000000000 --- a/external/Box2D/Dynamics/b2Body.h +++ /dev/null @@ -1,846 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_BODY_H -#define B2_BODY_H - -#include -#include -#include - -class b2Fixture; -class b2Joint; -class b2Contact; -class b2Controller; -class b2World; -struct b2FixtureDef; -struct b2JointEdge; -struct b2ContactEdge; - -/// The body type. -/// static: zero mass, zero velocity, may be manually moved -/// kinematic: zero mass, non-zero velocity set by user, moved by solver -/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver -enum b2BodyType -{ - b2_staticBody = 0, - b2_kinematicBody, - b2_dynamicBody - - // TODO_ERIN - //b2_bulletBody, -}; - -/// A body definition holds all the data needed to construct a rigid body. -/// You can safely re-use body definitions. Shapes are added to a body after construction. -struct b2BodyDef -{ - /// This constructor sets the body definition default values. - b2BodyDef() - { - userData = NULL; - position.Set(0.0f, 0.0f); - angle = 0.0f; - linearVelocity.Set(0.0f, 0.0f); - angularVelocity = 0.0f; - linearDamping = 0.0f; - angularDamping = 0.0f; - allowSleep = true; - awake = true; - fixedRotation = false; - bullet = false; - type = b2_staticBody; - active = true; - gravityScale = 1.0f; - } - - /// The body type: static, kinematic, or dynamic. - /// Note: if a dynamic body would have zero mass, the mass is set to one. - b2BodyType type; - - /// The world position of the body. Avoid creating bodies at the origin - /// since this can lead to many overlapping shapes. - b2Vec2 position; - - /// The world angle of the body in radians. - float32 angle; - - /// The linear velocity of the body's origin in world co-ordinates. - b2Vec2 linearVelocity; - - /// The angular velocity of the body. - float32 angularVelocity; - - /// Linear damping is use to reduce the linear velocity. The damping parameter - /// can be larger than 1.0f but the damping effect becomes sensitive to the - /// time step when the damping parameter is large. - float32 linearDamping; - - /// Angular damping is use to reduce the angular velocity. The damping parameter - /// can be larger than 1.0f but the damping effect becomes sensitive to the - /// time step when the damping parameter is large. - float32 angularDamping; - - /// Set this flag to false if this body should never fall asleep. Note that - /// this increases CPU usage. - bool allowSleep; - - /// Is this body initially awake or sleeping? - bool awake; - - /// Should this body be prevented from rotating? Useful for characters. - bool fixedRotation; - - /// Is this a fast moving body that should be prevented from tunneling through - /// other moving bodies? Note that all bodies are prevented from tunneling through - /// kinematic and static bodies. This setting is only considered on dynamic bodies. - /// @warning You should use this flag sparingly since it increases processing time. - bool bullet; - - /// Does this body start out active? - bool active; - - /// Use this to store application specific body data. - void* userData; - - /// Scale the gravity applied to this body. - float32 gravityScale; -}; - -/// A rigid body. These are created via b2World::CreateBody. -class b2Body -{ -public: - /// Creates a fixture and attach it to this body. Use this function if you need - /// to set some fixture parameters, like friction. Otherwise you can create the - /// fixture directly from a shape. - /// If the density is non-zero, this function automatically updates the mass of the body. - /// Contacts are not created until the next time step. - /// @param def the fixture definition. - /// @warning This function is locked during callbacks. - b2Fixture* CreateFixture(const b2FixtureDef* def); - - /// Creates a fixture from a shape and attach it to this body. - /// This is a convenience function. Use b2FixtureDef if you need to set parameters - /// like friction, restitution, user data, or filtering. - /// If the density is non-zero, this function automatically updates the mass of the body. - /// @param shape the shape to be cloned. - /// @param density the shape density (set to zero for static bodies). - /// @warning This function is locked during callbacks. - b2Fixture* CreateFixture(const b2Shape* shape, float32 density); - - /// Destroy a fixture. This removes the fixture from the broad-phase and - /// destroys all contacts associated with this fixture. This will - /// automatically adjust the mass of the body if the body is dynamic and the - /// fixture has positive density. - /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. - /// @param fixture the fixture to be removed. - /// @warning This function is locked during callbacks. - void DestroyFixture(b2Fixture* fixture); - - /// Set the position of the body's origin and rotation. - /// This breaks any contacts and wakes the other bodies. - /// Manipulating a body's transform may cause non-physical behavior. - /// @param position the world position of the body's local origin. - /// @param angle the world rotation in radians. - void SetTransform(const b2Vec2& position, float32 angle); - - /// Get the body transform for the body's origin. - /// @return the world transform of the body's origin. - const b2Transform& GetTransform() const; - - /// Get the world body origin position. - /// @return the world position of the body's origin. - const b2Vec2& GetPosition() const; - - /// Get the angle in radians. - /// @return the current world rotation angle in radians. - float32 GetAngle() const; - - /// Get the world position of the center of mass. - const b2Vec2& GetWorldCenter() const; - - /// Get the local position of the center of mass. - const b2Vec2& GetLocalCenter() const; - - /// Set the linear velocity of the center of mass. - /// @param v the new linear velocity of the center of mass. - void SetLinearVelocity(const b2Vec2& v); - - /// Get the linear velocity of the center of mass. - /// @return the linear velocity of the center of mass. - b2Vec2 GetLinearVelocity() const; - - /// Set the angular velocity. - /// @param omega the new angular velocity in radians/second. - void SetAngularVelocity(float32 omega); - - /// Get the angular velocity. - /// @return the angular velocity in radians/second. - float32 GetAngularVelocity() const; - - /// Apply a force at a world point. If the force is not - /// applied at the center of mass, it will generate a torque and - /// affect the angular velocity. This wakes up the body. - /// @param force the world force vector, usually in Newtons (N). - /// @param point the world position of the point of application. - void ApplyForce(const b2Vec2& force, const b2Vec2& point); - - /// Apply a force to the center of mass. This wakes up the body. - /// @param force the world force vector, usually in Newtons (N). - void ApplyForceToCenter(const b2Vec2& force); - - /// Apply a torque. This affects the angular velocity - /// without affecting the linear velocity of the center of mass. - /// This wakes up the body. - /// @param torque about the z-axis (out of the screen), usually in N-m. - void ApplyTorque(float32 torque); - - /// Apply an impulse at a point. This immediately modifies the velocity. - /// It also modifies the angular velocity if the point of application - /// is not at the center of mass. This wakes up the body. - /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. - /// @param point the world position of the point of application. - void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point); - - /// Apply an angular impulse. - /// @param impulse the angular impulse in units of kg*m*m/s - void ApplyAngularImpulse(float32 impulse); - - /// Get the total mass of the body. - /// @return the mass, usually in kilograms (kg). - float32 GetMass() const; - - /// Get the rotational inertia of the body about the local origin. - /// @return the rotational inertia, usually in kg-m^2. - float32 GetInertia() const; - - /// Get the mass data of the body. - /// @return a struct containing the mass, inertia and center of the body. - void GetMassData(b2MassData* data) const; - - /// Set the mass properties to override the mass properties of the fixtures. - /// Note that this changes the center of mass position. - /// Note that creating or destroying fixtures can also alter the mass. - /// This function has no effect if the body isn't dynamic. - /// @param massData the mass properties. - void SetMassData(const b2MassData* data); - - /// This resets the mass properties to the sum of the mass properties of the fixtures. - /// This normally does not need to be called unless you called SetMassData to override - /// the mass and you later want to reset the mass. - void ResetMassData(); - - /// Get the world coordinates of a point given the local coordinates. - /// @param localPoint a point on the body measured relative the the body's origin. - /// @return the same point expressed in world coordinates. - b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; - - /// Get the world coordinates of a vector given the local coordinates. - /// @param localVector a vector fixed in the body. - /// @return the same vector expressed in world coordinates. - b2Vec2 GetWorldVector(const b2Vec2& localVector) const; - - /// Gets a local point relative to the body's origin given a world point. - /// @param a point in world coordinates. - /// @return the corresponding local point relative to the body's origin. - b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; - - /// Gets a local vector given a world vector. - /// @param a vector in world coordinates. - /// @return the corresponding local vector. - b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; - - /// Get the world linear velocity of a world point attached to this body. - /// @param a point in world coordinates. - /// @return the world velocity of a point. - b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; - - /// Get the world velocity of a local point. - /// @param a point in local coordinates. - /// @return the world velocity of a point. - b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; - - /// Get the linear damping of the body. - float32 GetLinearDamping() const; - - /// Set the linear damping of the body. - void SetLinearDamping(float32 linearDamping); - - /// Get the angular damping of the body. - float32 GetAngularDamping() const; - - /// Set the angular damping of the body. - void SetAngularDamping(float32 angularDamping); - - /// Get the gravity scale of the body. - float32 GetGravityScale() const; - - /// Set the gravity scale of the body. - void SetGravityScale(float32 scale); - - /// Set the type of this body. This may alter the mass and velocity. - void SetType(b2BodyType type); - - /// Get the type of this body. - b2BodyType GetType() const; - - /// Should this body be treated like a bullet for continuous collision detection? - void SetBullet(bool flag); - - /// Is this body treated like a bullet for continuous collision detection? - bool IsBullet() const; - - /// You can disable sleeping on this body. If you disable sleeping, the - /// body will be woken. - void SetSleepingAllowed(bool flag); - - /// Is this body allowed to sleep - bool IsSleepingAllowed() const; - - /// Set the sleep state of the body. A sleeping body has very - /// low CPU cost. - /// @param flag set to true to put body to sleep, false to wake it. - void SetAwake(bool flag); - - /// Get the sleeping state of this body. - /// @return true if the body is sleeping. - bool IsAwake() const; - - /// Set the active state of the body. An inactive body is not - /// simulated and cannot be collided with or woken up. - /// If you pass a flag of true, all fixtures will be added to the - /// broad-phase. - /// If you pass a flag of false, all fixtures will be removed from - /// the broad-phase and all contacts will be destroyed. - /// Fixtures and joints are otherwise unaffected. You may continue - /// to create/destroy fixtures and joints on inactive bodies. - /// Fixtures on an inactive body are implicitly inactive and will - /// not participate in collisions, ray-casts, or queries. - /// Joints connected to an inactive body are implicitly inactive. - /// An inactive body is still owned by a b2World object and remains - /// in the body list. - void SetActive(bool flag); - - /// Get the active state of the body. - bool IsActive() const; - - /// Set this body to have fixed rotation. This causes the mass - /// to be reset. - void SetFixedRotation(bool flag); - - /// Does this body have fixed rotation? - bool IsFixedRotation() const; - - /// Get the list of all fixtures attached to this body. - b2Fixture* GetFixtureList(); - const b2Fixture* GetFixtureList() const; - - /// Get the list of all joints attached to this body. - b2JointEdge* GetJointList(); - const b2JointEdge* GetJointList() const; - - /// Get the list of all contacts attached to this body. - /// @warning this list changes during the time step and you may - /// miss some collisions if you don't use b2ContactListener. - b2ContactEdge* GetContactList(); - const b2ContactEdge* GetContactList() const; - - /// Get the next body in the world's body list. - b2Body* GetNext(); - const b2Body* GetNext() const; - - /// Get the user data pointer that was provided in the body definition. - void* GetUserData() const; - - /// Set the user data. Use this to store your application specific data. - void SetUserData(void* data); - - /// Get the parent world of this body. - b2World* GetWorld(); - const b2World* GetWorld() const; - - /// Dump this body to a log file - void Dump(); - -private: - - friend class b2World; - friend class b2Island; - friend class b2ContactManager; - friend class b2ContactSolver; - friend class b2Contact; - - friend class b2DistanceJoint; - friend class b2GearJoint; - friend class b2WheelJoint; - friend class b2MouseJoint; - friend class b2PrismaticJoint; - friend class b2PulleyJoint; - friend class b2RevoluteJoint; - friend class b2WeldJoint; - friend class b2FrictionJoint; - friend class b2RopeJoint; - - // m_flags - enum - { - e_islandFlag = 0x0001, - e_awakeFlag = 0x0002, - e_autoSleepFlag = 0x0004, - e_bulletFlag = 0x0008, - e_fixedRotationFlag = 0x0010, - e_activeFlag = 0x0020, - e_toiFlag = 0x0040 - }; - - b2Body(const b2BodyDef* bd, b2World* world); - ~b2Body(); - - void SynchronizeFixtures(); - void SynchronizeTransform(); - - // This is used to prevent connected bodies from colliding. - // It may lie, depending on the collideConnected flag. - bool ShouldCollide(const b2Body* other) const; - - void Advance(float32 t); - - b2BodyType m_type; - - uint16 m_flags; - - int32 m_islandIndex; - - b2Transform m_xf; // the body origin transform - b2Sweep m_sweep; // the swept motion for CCD - - b2Vec2 m_linearVelocity; - float32 m_angularVelocity; - - b2Vec2 m_force; - float32 m_torque; - - b2World* m_world; - b2Body* m_prev; - b2Body* m_next; - - b2Fixture* m_fixtureList; - int32 m_fixtureCount; - - b2JointEdge* m_jointList; - b2ContactEdge* m_contactList; - - float32 m_mass, m_invMass; - - // Rotational inertia about the center of mass. - float32 m_I, m_invI; - - float32 m_linearDamping; - float32 m_angularDamping; - float32 m_gravityScale; - - float32 m_sleepTime; - - void* m_userData; -}; - -inline b2BodyType b2Body::GetType() const -{ - return m_type; -} - -inline const b2Transform& b2Body::GetTransform() const -{ - return m_xf; -} - -inline const b2Vec2& b2Body::GetPosition() const -{ - return m_xf.p; -} - -inline float32 b2Body::GetAngle() const -{ - return m_sweep.a; -} - -inline const b2Vec2& b2Body::GetWorldCenter() const -{ - return m_sweep.c; -} - -inline const b2Vec2& b2Body::GetLocalCenter() const -{ - return m_sweep.localCenter; -} - -inline void b2Body::SetLinearVelocity(const b2Vec2& v) -{ - if (m_type == b2_staticBody) - { - return; - } - - if (b2Dot(v,v) > 0.0f) - { - SetAwake(true); - } - - m_linearVelocity = v; -} - -inline b2Vec2 b2Body::GetLinearVelocity() const -{ - return m_linearVelocity; -} - -inline void b2Body::SetAngularVelocity(float32 w) -{ - if (m_type == b2_staticBody) - { - return; - } - - if (w * w > 0.0f) - { - SetAwake(true); - } - - m_angularVelocity = w; -} - -inline float32 b2Body::GetAngularVelocity() const -{ - return m_angularVelocity; -} - -inline float32 b2Body::GetMass() const -{ - return m_mass; -} - -inline float32 b2Body::GetInertia() const -{ - return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); -} - -inline void b2Body::GetMassData(b2MassData* data) const -{ - data->mass = m_mass; - data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); - data->center = m_sweep.localCenter; -} - -inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const -{ - return b2Mul(m_xf, localPoint); -} - -inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const -{ - return b2Mul(m_xf.q, localVector); -} - -inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const -{ - return b2MulT(m_xf, worldPoint); -} - -inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const -{ - return b2MulT(m_xf.q, worldVector); -} - -inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const -{ - return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); -} - -inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const -{ - return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); -} - -inline float32 b2Body::GetLinearDamping() const -{ - return m_linearDamping; -} - -inline void b2Body::SetLinearDamping(float32 linearDamping) -{ - m_linearDamping = linearDamping; -} - -inline float32 b2Body::GetAngularDamping() const -{ - return m_angularDamping; -} - -inline void b2Body::SetAngularDamping(float32 angularDamping) -{ - m_angularDamping = angularDamping; -} - -inline float32 b2Body::GetGravityScale() const -{ - return m_gravityScale; -} - -inline void b2Body::SetGravityScale(float32 scale) -{ - m_gravityScale = scale; -} - -inline void b2Body::SetBullet(bool flag) -{ - if (flag) - { - m_flags |= e_bulletFlag; - } - else - { - m_flags &= ~e_bulletFlag; - } -} - -inline bool b2Body::IsBullet() const -{ - return (m_flags & e_bulletFlag) == e_bulletFlag; -} - -inline void b2Body::SetAwake(bool flag) -{ - if (flag) - { - if ((m_flags & e_awakeFlag) == 0) - { - m_flags |= e_awakeFlag; - m_sleepTime = 0.0f; - } - } - else - { - m_flags &= ~e_awakeFlag; - m_sleepTime = 0.0f; - m_linearVelocity.SetZero(); - m_angularVelocity = 0.0f; - m_force.SetZero(); - m_torque = 0.0f; - } -} - -inline bool b2Body::IsAwake() const -{ - return (m_flags & e_awakeFlag) == e_awakeFlag; -} - -inline bool b2Body::IsActive() const -{ - return (m_flags & e_activeFlag) == e_activeFlag; -} - -inline void b2Body::SetFixedRotation(bool flag) -{ - if (flag) - { - m_flags |= e_fixedRotationFlag; - } - else - { - m_flags &= ~e_fixedRotationFlag; - } - - ResetMassData(); -} - -inline bool b2Body::IsFixedRotation() const -{ - return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; -} - -inline void b2Body::SetSleepingAllowed(bool flag) -{ - if (flag) - { - m_flags |= e_autoSleepFlag; - } - else - { - m_flags &= ~e_autoSleepFlag; - SetAwake(true); - } -} - -inline bool b2Body::IsSleepingAllowed() const -{ - return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; -} - -inline b2Fixture* b2Body::GetFixtureList() -{ - return m_fixtureList; -} - -inline const b2Fixture* b2Body::GetFixtureList() const -{ - return m_fixtureList; -} - -inline b2JointEdge* b2Body::GetJointList() -{ - return m_jointList; -} - -inline const b2JointEdge* b2Body::GetJointList() const -{ - return m_jointList; -} - -inline b2ContactEdge* b2Body::GetContactList() -{ - return m_contactList; -} - -inline const b2ContactEdge* b2Body::GetContactList() const -{ - return m_contactList; -} - -inline b2Body* b2Body::GetNext() -{ - return m_next; -} - -inline const b2Body* b2Body::GetNext() const -{ - return m_next; -} - -inline void b2Body::SetUserData(void* data) -{ - m_userData = data; -} - -inline void* b2Body::GetUserData() const -{ - return m_userData; -} - -inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_force += force; - m_torque += b2Cross(point - m_sweep.c, force); -} - -inline void b2Body::ApplyForceToCenter(const b2Vec2& force) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_force += force; -} - -inline void b2Body::ApplyTorque(float32 torque) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_torque += torque; -} - -inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - m_linearVelocity += m_invMass * impulse; - m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); -} - -inline void b2Body::ApplyAngularImpulse(float32 impulse) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - m_angularVelocity += m_invI * impulse; -} - -inline void b2Body::SynchronizeTransform() -{ - m_xf.q.Set(m_sweep.a); - m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); -} - -inline void b2Body::Advance(float32 alpha) -{ - // Advance to the new safe time. This doesn't sync the broad-phase. - m_sweep.Advance(alpha); - m_sweep.c = m_sweep.c0; - m_sweep.a = m_sweep.a0; - m_xf.q.Set(m_sweep.a); - m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); -} - -inline b2World* b2Body::GetWorld() -{ - return m_world; -} - -inline const b2World* b2Body::GetWorld() const -{ - return m_world; -} - -#endif diff --git a/external/Box2D/Dynamics/b2ContactManager.cpp b/external/Box2D/Dynamics/b2ContactManager.cpp deleted file mode 100644 index c14cc4ce45..0000000000 --- a/external/Box2D/Dynamics/b2ContactManager.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include - -b2ContactFilter b2_defaultFilter; -b2ContactListener b2_defaultListener; - -b2ContactManager::b2ContactManager() -{ - m_contactList = NULL; - m_contactCount = 0; - m_contactFilter = &b2_defaultFilter; - m_contactListener = &b2_defaultListener; - m_allocator = NULL; -} - -void b2ContactManager::Destroy(b2Contact* c) -{ - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - if (m_contactListener && c->IsTouching()) - { - m_contactListener->EndContact(c); - } - - // Remove from the world. - if (c->m_prev) - { - c->m_prev->m_next = c->m_next; - } - - if (c->m_next) - { - c->m_next->m_prev = c->m_prev; - } - - if (c == m_contactList) - { - m_contactList = c->m_next; - } - - // Remove from body 1 - if (c->m_nodeA.prev) - { - c->m_nodeA.prev->next = c->m_nodeA.next; - } - - if (c->m_nodeA.next) - { - c->m_nodeA.next->prev = c->m_nodeA.prev; - } - - if (&c->m_nodeA == bodyA->m_contactList) - { - bodyA->m_contactList = c->m_nodeA.next; - } - - // Remove from body 2 - if (c->m_nodeB.prev) - { - c->m_nodeB.prev->next = c->m_nodeB.next; - } - - if (c->m_nodeB.next) - { - c->m_nodeB.next->prev = c->m_nodeB.prev; - } - - if (&c->m_nodeB == bodyB->m_contactList) - { - bodyB->m_contactList = c->m_nodeB.next; - } - - // Call the factory. - b2Contact::Destroy(c, m_allocator); - --m_contactCount; -} - -// This is the top level collision call for the time step. Here -// all the narrow phase collision is processed for the world -// contact list. -void b2ContactManager::Collide() -{ - // Update awake contacts. - b2Contact* c = m_contactList; - while (c) - { - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - // Is this contact flagged for filtering? - if (c->m_flags & b2Contact::e_filterFlag) - { - // Should these bodies collide? - if (bodyB->ShouldCollide(bodyA) == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // Check user filtering. - if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // Clear the filtering flag. - c->m_flags &= ~b2Contact::e_filterFlag; - } - - bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; - bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; - - // At least one body must be awake and it must be dynamic or kinematic. - if (activeA == false && activeB == false) - { - c = c->GetNext(); - continue; - } - - int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; - int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; - bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); - - // Here we destroy contacts that cease to overlap in the broad-phase. - if (overlap == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // The contact persists. - c->Update(m_contactListener); - c = c->GetNext(); - } -} - -void b2ContactManager::FindNewContacts() -{ - m_broadPhase.UpdatePairs(this); -} - -void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) -{ - b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; - b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; - - b2Fixture* fixtureA = proxyA->fixture; - b2Fixture* fixtureB = proxyB->fixture; - - int32 indexA = proxyA->childIndex; - int32 indexB = proxyB->childIndex; - - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - // Are the fixtures on the same body? - if (bodyA == bodyB) - { - return; - } - - // TODO_ERIN use a hash table to remove a potential bottleneck when both - // bodies have a lot of contacts. - // Does a contact already exist? - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - b2Fixture* fA = edge->contact->GetFixtureA(); - b2Fixture* fB = edge->contact->GetFixtureB(); - int32 iA = edge->contact->GetChildIndexA(); - int32 iB = edge->contact->GetChildIndexB(); - - if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) - { - // A contact already exists. - return; - } - - if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) - { - // A contact already exists. - return; - } - } - - edge = edge->next; - } - - // Does a joint override collision? Is at least one body dynamic? - if (bodyB->ShouldCollide(bodyA) == false) - { - return; - } - - // Check user filtering. - if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) - { - return; - } - - // Call the factory. - b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); - if (c == NULL) - { - return; - } - - // Contact creation may swap fixtures. - fixtureA = c->GetFixtureA(); - fixtureB = c->GetFixtureB(); - indexA = c->GetChildIndexA(); - indexB = c->GetChildIndexB(); - bodyA = fixtureA->GetBody(); - bodyB = fixtureB->GetBody(); - - // Insert into the world. - c->m_prev = NULL; - c->m_next = m_contactList; - if (m_contactList != NULL) - { - m_contactList->m_prev = c; - } - m_contactList = c; - - // Connect to island graph. - - // Connect to body A - c->m_nodeA.contact = c; - c->m_nodeA.other = bodyB; - - c->m_nodeA.prev = NULL; - c->m_nodeA.next = bodyA->m_contactList; - if (bodyA->m_contactList != NULL) - { - bodyA->m_contactList->prev = &c->m_nodeA; - } - bodyA->m_contactList = &c->m_nodeA; - - // Connect to body B - c->m_nodeB.contact = c; - c->m_nodeB.other = bodyA; - - c->m_nodeB.prev = NULL; - c->m_nodeB.next = bodyB->m_contactList; - if (bodyB->m_contactList != NULL) - { - bodyB->m_contactList->prev = &c->m_nodeB; - } - bodyB->m_contactList = &c->m_nodeB; - - // Wake up the bodies - bodyA->SetAwake(true); - bodyB->SetAwake(true); - - ++m_contactCount; -} diff --git a/external/Box2D/Dynamics/b2ContactManager.h b/external/Box2D/Dynamics/b2ContactManager.h deleted file mode 100644 index 9cb5718145..0000000000 --- a/external/Box2D/Dynamics/b2ContactManager.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_MANAGER_H -#define B2_CONTACT_MANAGER_H - -#include - -class b2Contact; -class b2ContactFilter; -class b2ContactListener; -class b2BlockAllocator; - -// Delegate of b2World. -class b2ContactManager -{ -public: - b2ContactManager(); - - // Broad-phase callback. - void AddPair(void* proxyUserDataA, void* proxyUserDataB); - - void FindNewContacts(); - - void Destroy(b2Contact* c); - - void Collide(); - - b2BroadPhase m_broadPhase; - b2Contact* m_contactList; - int32 m_contactCount; - b2ContactFilter* m_contactFilter; - b2ContactListener* m_contactListener; - b2BlockAllocator* m_allocator; -}; - -#endif diff --git a/external/Box2D/Dynamics/b2Fixture.cpp b/external/Box2D/Dynamics/b2Fixture.cpp deleted file mode 100644 index 774a78e5bb..0000000000 --- a/external/Box2D/Dynamics/b2Fixture.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -b2Fixture::b2Fixture() -{ - m_userData = NULL; - m_body = NULL; - m_next = NULL; - m_proxies = NULL; - m_proxyCount = 0; - m_shape = NULL; - m_density = 0.0f; -} - -void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) -{ - m_userData = def->userData; - m_friction = def->friction; - m_restitution = def->restitution; - - m_body = body; - m_next = NULL; - - m_filter = def->filter; - - m_isSensor = def->isSensor; - - m_shape = def->shape->Clone(allocator); - - // Reserve proxy space - int32 childCount = m_shape->GetChildCount(); - m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); - for (int32 i = 0; i < childCount; ++i) - { - m_proxies[i].fixture = NULL; - m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; - } - m_proxyCount = 0; - - m_density = def->density; -} - -void b2Fixture::Destroy(b2BlockAllocator* allocator) -{ - // The proxies must be destroyed before calling this. - b2Assert(m_proxyCount == 0); - - // Free the proxy array. - int32 childCount = m_shape->GetChildCount(); - allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); - m_proxies = NULL; - - // Free the child shape. - switch (m_shape->m_type) - { - case b2Shape::e_circle: - { - b2CircleShape* s = (b2CircleShape*)m_shape; - s->~b2CircleShape(); - allocator->Free(s, sizeof(b2CircleShape)); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* s = (b2EdgeShape*)m_shape; - s->~b2EdgeShape(); - allocator->Free(s, sizeof(b2EdgeShape)); - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* s = (b2PolygonShape*)m_shape; - s->~b2PolygonShape(); - allocator->Free(s, sizeof(b2PolygonShape)); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* s = (b2ChainShape*)m_shape; - s->~b2ChainShape(); - allocator->Free(s, sizeof(b2ChainShape)); - } - break; - - default: - b2Assert(false); - break; - } - - m_shape = NULL; -} - -void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) -{ - b2Assert(m_proxyCount == 0); - - // Create proxies in the broad-phase. - m_proxyCount = m_shape->GetChildCount(); - - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - m_shape->ComputeAABB(&proxy->aabb, xf, i); - proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); - proxy->fixture = this; - proxy->childIndex = i; - } -} - -void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) -{ - // Destroy proxies in the broad-phase. - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - broadPhase->DestroyProxy(proxy->proxyId); - proxy->proxyId = b2BroadPhase::e_nullProxy; - } - - m_proxyCount = 0; -} - -void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) -{ - if (m_proxyCount == 0) - { - return; - } - - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - - // Compute an AABB that covers the swept shape (may miss some rotation effect). - b2AABB aabb1, aabb2; - m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); - m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); - - proxy->aabb.Combine(aabb1, aabb2); - - b2Vec2 displacement = transform2.p - transform1.p; - - broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); - } -} - -void b2Fixture::SetFilterData(const b2Filter& filter) -{ - m_filter = filter; - - Refilter(); -} - -void b2Fixture::Refilter() -{ - if (m_body == NULL) - { - return; - } - - // Flag associated contacts for filtering. - b2ContactEdge* edge = m_body->GetContactList(); - while (edge) - { - b2Contact* contact = edge->contact; - b2Fixture* fixtureA = contact->GetFixtureA(); - b2Fixture* fixtureB = contact->GetFixtureB(); - if (fixtureA == this || fixtureB == this) - { - contact->FlagForFiltering(); - } - - edge = edge->next; - } - - b2World* world = m_body->GetWorld(); - - if (world == NULL) - { - return; - } - - // Touch each proxy so that new pairs may be created - b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; - for (int32 i = 0; i < m_proxyCount; ++i) - { - broadPhase->TouchProxy(m_proxies[i].proxyId); - } -} - -void b2Fixture::SetSensor(bool sensor) -{ - if (sensor != m_isSensor) - { - m_body->SetAwake(true); - m_isSensor = sensor; - } -} - -void b2Fixture::Dump(int32 bodyIndex) -{ - b2Log(" b2FixtureDef fd;\n"); - b2Log(" fd.friction = %.15lef;\n", m_friction); - b2Log(" fd.restitution = %.15lef;\n", m_restitution); - b2Log(" fd.density = %.15lef;\n", m_density); - b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); - b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); - b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); - b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); - - switch (m_shape->m_type) - { - case b2Shape::e_circle: - { - b2CircleShape* s = (b2CircleShape*)m_shape; - b2Log(" b2CircleShape shape;\n"); - b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); - b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* s = (b2EdgeShape*)m_shape; - b2Log(" b2EdgeShape shape;\n"); - b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); - b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); - b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); - b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); - b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); - b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); - b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* s = (b2PolygonShape*)m_shape; - b2Log(" b2PolygonShape shape;\n"); - b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); - for (int32 i = 0; i < s->m_vertexCount; ++i) - { - b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); - } - b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* s = (b2ChainShape*)m_shape; - b2Log(" b2ChainShape shape;\n"); - b2Log(" b2Vec2 vs[%d];\n", s->m_count); - for (int32 i = 0; i < s->m_count; ++i) - { - b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); - } - b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); - b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); - b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); - b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); - b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); - } - break; - - default: - return; - } - - b2Log("\n"); - b2Log(" fd.shape = &shape;\n"); - b2Log("\n"); - b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); -} diff --git a/external/Box2D/Dynamics/b2Fixture.h b/external/Box2D/Dynamics/b2Fixture.h deleted file mode 100644 index d390410b93..0000000000 --- a/external/Box2D/Dynamics/b2Fixture.h +++ /dev/null @@ -1,345 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_FIXTURE_H -#define B2_FIXTURE_H - -#include -#include -#include - -class b2BlockAllocator; -class b2Body; -class b2BroadPhase; -class b2Fixture; - -/// This holds contact filtering data. -struct b2Filter -{ - b2Filter() - { - categoryBits = 0x0001; - maskBits = 0xFFFF; - groupIndex = 0; - } - - /// The collision category bits. Normally you would just set one bit. - uint16 categoryBits; - - /// The collision mask bits. This states the categories that this - /// shape would accept for collision. - uint16 maskBits; - - /// Collision groups allow a certain group of objects to never collide (negative) - /// or always collide (positive). Zero means no collision group. Non-zero group - /// filtering always wins against the mask bits. - int16 groupIndex; -}; - -/// A fixture definition is used to create a fixture. This class defines an -/// abstract fixture definition. You can reuse fixture definitions safely. -struct b2FixtureDef -{ - /// The constructor sets the default fixture definition values. - b2FixtureDef() - { - shape = NULL; - userData = NULL; - friction = 0.2f; - restitution = 0.0f; - density = 0.0f; - isSensor = false; - } - - /// The shape, this must be set. The shape will be cloned, so you - /// can create the shape on the stack. - const b2Shape* shape; - - /// Use this to store application specific fixture data. - void* userData; - - /// The friction coefficient, usually in the range [0,1]. - float32 friction; - - /// The restitution (elasticity) usually in the range [0,1]. - float32 restitution; - - /// The density, usually in kg/m^2. - float32 density; - - /// A sensor shape collects contact information but never generates a collision - /// response. - bool isSensor; - - /// Contact filtering data. - b2Filter filter; -}; - -/// This proxy is used internally to connect fixtures to the broad-phase. -struct b2FixtureProxy -{ - b2AABB aabb; - b2Fixture* fixture; - int32 childIndex; - int32 proxyId; -}; - -/// A fixture is used to attach a shape to a body for collision detection. A fixture -/// inherits its transform from its parent. Fixtures hold additional non-geometric data -/// such as friction, collision filters, etc. -/// Fixtures are created via b2Body::CreateFixture. -/// @warning you cannot reuse fixtures. -class b2Fixture -{ -public: - /// Get the type of the child shape. You can use this to down cast to the concrete shape. - /// @return the shape type. - b2Shape::Type GetType() const; - - /// Get the child shape. You can modify the child shape, however you should not change the - /// number of vertices because this will crash some collision caching mechanisms. - /// Manipulating the shape may lead to non-physical behavior. - b2Shape* GetShape(); - const b2Shape* GetShape() const; - - /// Set if this fixture is a sensor. - void SetSensor(bool sensor); - - /// Is this fixture a sensor (non-solid)? - /// @return the true if the shape is a sensor. - bool IsSensor() const; - - /// Set the contact filtering data. This will not update contacts until the next time - /// step when either parent body is active and awake. - /// This automatically calls Refilter. - void SetFilterData(const b2Filter& filter); - - /// Get the contact filtering data. - const b2Filter& GetFilterData() const; - - /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. - void Refilter(); - - /// Get the parent body of this fixture. This is NULL if the fixture is not attached. - /// @return the parent body. - b2Body* GetBody(); - const b2Body* GetBody() const; - - /// Get the next fixture in the parent body's fixture list. - /// @return the next shape. - b2Fixture* GetNext(); - const b2Fixture* GetNext() const; - - /// Get the user data that was assigned in the fixture definition. Use this to - /// store your application specific data. - void* GetUserData() const; - - /// Set the user data. Use this to store your application specific data. - void SetUserData(void* data); - - /// Test a point for containment in this fixture. - /// @param p a point in world coordinates. - bool TestPoint(const b2Vec2& p) const; - - /// Cast a ray against this shape. - /// @param output the ray-cast results. - /// @param input the ray-cast input parameters. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; - - /// Get the mass data for this fixture. The mass data is based on the density and - /// the shape. The rotational inertia is about the shape's origin. This operation - /// may be expensive. - void GetMassData(b2MassData* massData) const; - - /// Set the density of this fixture. This will _not_ automatically adjust the mass - /// of the body. You must call b2Body::ResetMassData to update the body's mass. - void SetDensity(float32 density); - - /// Get the density of this fixture. - float32 GetDensity() const; - - /// Get the coefficient of friction. - float32 GetFriction() const; - - /// Set the coefficient of friction. This will _not_ change the friction of - /// existing contacts. - void SetFriction(float32 friction); - - /// Get the coefficient of restitution. - float32 GetRestitution() const; - - /// Set the coefficient of restitution. This will _not_ change the restitution of - /// existing contacts. - void SetRestitution(float32 restitution); - - /// Get the fixture's AABB. This AABB may be enlarge and/or stale. - /// If you need a more accurate AABB, compute it using the shape and - /// the body transform. - const b2AABB& GetAABB(int32 childIndex) const; - - /// Dump this fixture to the log file. - void Dump(int32 bodyIndex); - -protected: - - friend class b2Body; - friend class b2World; - friend class b2Contact; - friend class b2ContactManager; - - b2Fixture(); - - // We need separation create/destroy functions from the constructor/destructor because - // the destructor cannot access the allocator (no destructor arguments allowed by C++). - void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); - void Destroy(b2BlockAllocator* allocator); - - // These support body activation/deactivation. - void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); - void DestroyProxies(b2BroadPhase* broadPhase); - - void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); - - float32 m_density; - - b2Fixture* m_next; - b2Body* m_body; - - b2Shape* m_shape; - - float32 m_friction; - float32 m_restitution; - - b2FixtureProxy* m_proxies; - int32 m_proxyCount; - - b2Filter m_filter; - - bool m_isSensor; - - void* m_userData; -}; - -inline b2Shape::Type b2Fixture::GetType() const -{ - return m_shape->GetType(); -} - -inline b2Shape* b2Fixture::GetShape() -{ - return m_shape; -} - -inline const b2Shape* b2Fixture::GetShape() const -{ - return m_shape; -} - -inline bool b2Fixture::IsSensor() const -{ - return m_isSensor; -} - -inline const b2Filter& b2Fixture::GetFilterData() const -{ - return m_filter; -} - -inline void* b2Fixture::GetUserData() const -{ - return m_userData; -} - -inline void b2Fixture::SetUserData(void* data) -{ - m_userData = data; -} - -inline b2Body* b2Fixture::GetBody() -{ - return m_body; -} - -inline const b2Body* b2Fixture::GetBody() const -{ - return m_body; -} - -inline b2Fixture* b2Fixture::GetNext() -{ - return m_next; -} - -inline const b2Fixture* b2Fixture::GetNext() const -{ - return m_next; -} - -inline void b2Fixture::SetDensity(float32 density) -{ - b2Assert(b2IsValid(density) && density >= 0.0f); - m_density = density; -} - -inline float32 b2Fixture::GetDensity() const -{ - return m_density; -} - -inline float32 b2Fixture::GetFriction() const -{ - return m_friction; -} - -inline void b2Fixture::SetFriction(float32 friction) -{ - m_friction = friction; -} - -inline float32 b2Fixture::GetRestitution() const -{ - return m_restitution; -} - -inline void b2Fixture::SetRestitution(float32 restitution) -{ - m_restitution = restitution; -} - -inline bool b2Fixture::TestPoint(const b2Vec2& p) const -{ - return m_shape->TestPoint(m_body->GetTransform(), p); -} - -inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const -{ - return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); -} - -inline void b2Fixture::GetMassData(b2MassData* massData) const -{ - m_shape->ComputeMass(massData, m_density); -} - -inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const -{ - b2Assert(0 <= childIndex && childIndex < m_proxyCount); - return m_proxies[childIndex].aabb; -} - -#endif diff --git a/external/Box2D/Dynamics/b2Island.cpp b/external/Box2D/Dynamics/b2Island.cpp deleted file mode 100644 index e767d383d5..0000000000 --- a/external/Box2D/Dynamics/b2Island.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -Position Correction Notes -========================= -I tried the several algorithms for position correction of the 2D revolute joint. -I looked at these systems: -- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. -- suspension bridge with 30 1m long planks of length 1m. -- multi-link chain with 30 1m long links. - -Here are the algorithms: - -Baumgarte - A fraction of the position error is added to the velocity error. There is no -separate position solver. - -Pseudo Velocities - After the velocity solver and position integration, -the position error, Jacobian, and effective mass are recomputed. Then -the velocity constraints are solved with pseudo velocities and a fraction -of the position error is added to the pseudo velocity error. The pseudo -velocities are initialized to zero and there is no warm-starting. After -the position solver, the pseudo velocities are added to the positions. -This is also called the First Order World method or the Position LCP method. - -Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the -position error is re-computed for each constraint and the positions are updated -after the constraint is solved. The radius vectors (aka Jacobians) are -re-computed too (otherwise the algorithm has horrible instability). The pseudo -velocity states are not needed because they are effectively zero at the beginning -of each iteration. Since we have the current position error, we allow the -iterations to terminate early if the error becomes smaller than b2_linearSlop. - -Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed -each time a constraint is solved. - -Here are the results: -Baumgarte - this is the cheapest algorithm but it has some stability problems, -especially with the bridge. The chain links separate easily close to the root -and they jitter as they struggle to pull together. This is one of the most common -methods in the field. The big drawback is that the position correction artificially -affects the momentum, thus leading to instabilities and false bounce. I used a -bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller -factor makes joints and contacts more spongy. - -Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is -stable. However, joints still separate with large angular velocities. Drag the -simple pendulum in a circle quickly and the joint will separate. The chain separates -easily and does not recover. I used a bias factor of 0.2. A larger value lead to -the bridge collapsing when a heavy cube drops on it. - -Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo -Velocities, but in other ways it is worse. The bridge and chain are much more -stable, but the simple pendulum goes unstable at high angular velocities. - -Full NGS - stable in all tests. The joints display good stiffness. The bridge -still sags, but this is better than infinite forces. - -Recommendations -Pseudo Velocities are not really worthwhile because the bridge and chain cannot -recover from joint separation. In other cases the benefit over Baumgarte is small. - -Modified NGS is not a robust method for the revolute joint due to the violent -instability seen in the simple pendulum. Perhaps it is viable with other constraint -types, especially scalar constraints where the effective mass is a scalar. - -This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities -and is very fast. I don't think we can escape Baumgarte, especially in highly -demanding cases where high constraint fidelity is not needed. - -Full NGS is robust and easy on the eyes. I recommend this as an option for -higher fidelity simulation and certainly for suspension bridges and long chains. -Full NGS might be a good choice for ragdolls, especially motorized ragdolls where -joint separation can be problematic. The number of NGS iterations can be reduced -for better performance without harming robustness much. - -Each joint in a can be handled differently in the position solver. So I recommend -a system where the user can select the algorithm on a per joint basis. I would -probably default to the slower Full NGS and let the user select the faster -Baumgarte method in performance critical scenarios. -*/ - -/* -Cache Performance - -The Box2D solvers are dominated by cache misses. Data structures are designed -to increase the number of cache hits. Much of misses are due to random access -to body data. The constraint structures are iterated over linearly, which leads -to few cache misses. - -The bodies are not accessed during iteration. Instead read only data, such as -the mass values are stored with the constraints. The mutable data are the constraint -impulses and the bodies velocities/positions. The impulses are held inside the -constraint structures. The body velocities/positions are held in compact, temporary -arrays to increase the number of cache hits. Linear and angular velocity are -stored in a single array since multiple arrays lead to multiple misses. -*/ - -/* -2D Rotation - -R = [cos(theta) -sin(theta)] - [sin(theta) cos(theta) ] - -thetaDot = omega - -Let q1 = cos(theta), q2 = sin(theta). -R = [q1 -q2] - [q2 q1] - -q1Dot = -thetaDot * q2 -q2Dot = thetaDot * q1 - -q1_new = q1_old - dt * w * q2 -q2_new = q2_old + dt * w * q1 -then normalize. - -This might be faster than computing sin+cos. -However, we can compute sin+cos of the same angle fast. -*/ - -b2Island::b2Island( - int32 bodyCapacity, - int32 contactCapacity, - int32 jointCapacity, - b2StackAllocator* allocator, - b2ContactListener* listener) -{ - m_bodyCapacity = bodyCapacity; - m_contactCapacity = contactCapacity; - m_jointCapacity = jointCapacity; - m_bodyCount = 0; - m_contactCount = 0; - m_jointCount = 0; - - m_allocator = allocator; - m_listener = listener; - - m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); - m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); - m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); - - m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); - m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); -} - -b2Island::~b2Island() -{ - // Warning: the order should reverse the constructor order. - m_allocator->Free(m_positions); - m_allocator->Free(m_velocities); - m_allocator->Free(m_joints); - m_allocator->Free(m_contacts); - m_allocator->Free(m_bodies); -} - -void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) -{ - b2Timer timer; - - float32 h = step.dt; - - // Integrate velocities and apply damping. Initialize the body state. - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - - b2Vec2 c = b->m_sweep.c; - float32 a = b->m_sweep.a; - b2Vec2 v = b->m_linearVelocity; - float32 w = b->m_angularVelocity; - - // Store positions for continuous collision. - b->m_sweep.c0 = b->m_sweep.c; - b->m_sweep.a0 = b->m_sweep.a; - - if (b->m_type == b2_dynamicBody) - { - // Integrate velocities. - v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); - w += h * b->m_invI * b->m_torque; - - // Apply damping. - // ODE: dv/dt + c * v = 0 - // Solution: v(t) = v0 * exp(-c * t) - // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) - // v2 = exp(-c * dt) * v1 - // Taylor expansion: - // v2 = (1.0f - c * dt) * v1 - v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); - w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); - } - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - } - - timer.Reset(); - - // Solver data - b2SolverData solverData; - solverData.step = step; - solverData.positions = m_positions; - solverData.velocities = m_velocities; - - // Initialize velocity constraints. - b2ContactSolverDef contactSolverDef; - contactSolverDef.step = step; - contactSolverDef.contacts = m_contacts; - contactSolverDef.count = m_contactCount; - contactSolverDef.positions = m_positions; - contactSolverDef.velocities = m_velocities; - contactSolverDef.allocator = m_allocator; - - b2ContactSolver contactSolver(&contactSolverDef); - contactSolver.InitializeVelocityConstraints(); - - if (step.warmStarting) - { - contactSolver.WarmStart(); - } - - for (int32 i = 0; i < m_jointCount; ++i) - { - m_joints[i]->InitVelocityConstraints(solverData); - } - - profile->solveInit = timer.GetMilliseconds(); - - // Solve velocity constraints - timer.Reset(); - for (int32 i = 0; i < step.velocityIterations; ++i) - { - for (int32 j = 0; j < m_jointCount; ++j) - { - m_joints[j]->SolveVelocityConstraints(solverData); - } - - contactSolver.SolveVelocityConstraints(); - } - - // Store impulses for warm starting - contactSolver.StoreImpulses(); - profile->solveVelocity = timer.GetMilliseconds(); - - // Integrate positions - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Vec2 c = m_positions[i].c; - float32 a = m_positions[i].a; - b2Vec2 v = m_velocities[i].v; - float32 w = m_velocities[i].w; - - // Check for large velocities - b2Vec2 translation = h * v; - if (b2Dot(translation, translation) > b2_maxTranslationSquared) - { - float32 ratio = b2_maxTranslation / translation.Length(); - v *= ratio; - } - - float32 rotation = h * w; - if (rotation * rotation > b2_maxRotationSquared) - { - float32 ratio = b2_maxRotation / b2Abs(rotation); - w *= ratio; - } - - // Integrate - c += h * v; - a += h * w; - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - } - - // Solve position constraints - timer.Reset(); - bool positionSolved = false; - for (int32 i = 0; i < step.positionIterations; ++i) - { - bool contactsOkay = contactSolver.SolvePositionConstraints(); - - bool jointsOkay = true; - for (int32 i = 0; i < m_jointCount; ++i) - { - bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); - jointsOkay = jointsOkay && jointOkay; - } - - if (contactsOkay && jointsOkay) - { - // Exit early if the position errors are small. - positionSolved = true; - break; - } - } - - // Copy state buffers back to the bodies - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* body = m_bodies[i]; - body->m_sweep.c = m_positions[i].c; - body->m_sweep.a = m_positions[i].a; - body->m_linearVelocity = m_velocities[i].v; - body->m_angularVelocity = m_velocities[i].w; - body->SynchronizeTransform(); - } - - profile->solvePosition = timer.GetMilliseconds(); - - Report(contactSolver.m_velocityConstraints); - - if (allowSleep) - { - float32 minSleepTime = b2_maxFloat; - - const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; - const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; - - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - if (b->GetType() == b2_staticBody) - { - continue; - } - - if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || - b->m_angularVelocity * b->m_angularVelocity > angTolSqr || - b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) - { - b->m_sleepTime = 0.0f; - minSleepTime = 0.0f; - } - else - { - b->m_sleepTime += h; - minSleepTime = b2Min(minSleepTime, b->m_sleepTime); - } - } - - if (minSleepTime >= b2_timeToSleep && positionSolved) - { - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - b->SetAwake(false); - } - } - } -} - -void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) -{ - b2Assert(toiIndexA < m_bodyCount); - b2Assert(toiIndexB < m_bodyCount); - - // Initialize the body state. - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - m_positions[i].c = b->m_sweep.c; - m_positions[i].a = b->m_sweep.a; - m_velocities[i].v = b->m_linearVelocity; - m_velocities[i].w = b->m_angularVelocity; - } - - b2ContactSolverDef contactSolverDef; - contactSolverDef.contacts = m_contacts; - contactSolverDef.count = m_contactCount; - contactSolverDef.allocator = m_allocator; - contactSolverDef.step = subStep; - contactSolverDef.positions = m_positions; - contactSolverDef.velocities = m_velocities; - b2ContactSolver contactSolver(&contactSolverDef); - - // Solve position constraints. - for (int32 i = 0; i < subStep.positionIterations; ++i) - { - bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); - if (contactsOkay) - { - break; - } - } - -#if 0 - // Is the new position really safe? - for (int32 i = 0; i < m_contactCount; ++i) - { - b2Contact* c = m_contacts[i]; - b2Fixture* fA = c->GetFixtureA(); - b2Fixture* fB = c->GetFixtureB(); - - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - - b2DistanceInput input; - input.proxyA.Set(fA->GetShape(), indexA); - input.proxyB.Set(fB->GetShape(), indexB); - input.transformA = bA->GetTransform(); - input.transformB = bB->GetTransform(); - input.useRadii = false; - - b2DistanceOutput output; - b2SimplexCache cache; - cache.count = 0; - b2Distance(&output, &cache, &input); - - if (output.distance == 0 || cache.count == 3) - { - cache.count += 0; - } - } -#endif - - // Leap of faith to new safe state. - m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; - m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; - m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; - m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; - - // No warm starting is needed for TOI events because warm - // starting impulses were applied in the discrete solver. - contactSolver.InitializeVelocityConstraints(); - - // Solve velocity constraints. - for (int32 i = 0; i < subStep.velocityIterations; ++i) - { - contactSolver.SolveVelocityConstraints(); - } - - // Don't store the TOI contact forces for warm starting - // because they can be quite large. - - float32 h = subStep.dt; - - // Integrate positions - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Vec2 c = m_positions[i].c; - float32 a = m_positions[i].a; - b2Vec2 v = m_velocities[i].v; - float32 w = m_velocities[i].w; - - // Check for large velocities - b2Vec2 translation = h * v; - if (b2Dot(translation, translation) > b2_maxTranslationSquared) - { - float32 ratio = b2_maxTranslation / translation.Length(); - v *= ratio; - } - - float32 rotation = h * w; - if (rotation * rotation > b2_maxRotationSquared) - { - float32 ratio = b2_maxRotation / b2Abs(rotation); - w *= ratio; - } - - // Integrate - c += h * v; - a += h * w; - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - - // Sync bodies - b2Body* body = m_bodies[i]; - body->m_sweep.c = c; - body->m_sweep.a = a; - body->m_linearVelocity = v; - body->m_angularVelocity = w; - body->SynchronizeTransform(); - } - - Report(contactSolver.m_velocityConstraints); -} - -void b2Island::Report(const b2ContactVelocityConstraint* constraints) -{ - if (m_listener == NULL) - { - return; - } - - for (int32 i = 0; i < m_contactCount; ++i) - { - b2Contact* c = m_contacts[i]; - - const b2ContactVelocityConstraint* vc = constraints + i; - - b2ContactImpulse impulse; - impulse.count = vc->pointCount; - for (int32 j = 0; j < vc->pointCount; ++j) - { - impulse.normalImpulses[j] = vc->points[j].normalImpulse; - impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; - } - - m_listener->PostSolve(c, &impulse); - } -} diff --git a/external/Box2D/Dynamics/b2Island.h b/external/Box2D/Dynamics/b2Island.h deleted file mode 100644 index e0a6e41fc3..0000000000 --- a/external/Box2D/Dynamics/b2Island.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_ISLAND_H -#define B2_ISLAND_H - -#include -#include -#include - -class b2Contact; -class b2Joint; -class b2StackAllocator; -class b2ContactListener; -struct b2ContactVelocityConstraint; -struct b2Profile; - -/// This is an internal class. -class b2Island -{ -public: - b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, - b2StackAllocator* allocator, b2ContactListener* listener); - ~b2Island(); - - void Clear() - { - m_bodyCount = 0; - m_contactCount = 0; - m_jointCount = 0; - } - - void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); - - void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); - - void Add(b2Body* body) - { - b2Assert(m_bodyCount < m_bodyCapacity); - body->m_islandIndex = m_bodyCount; - m_bodies[m_bodyCount] = body; - ++m_bodyCount; - } - - void Add(b2Contact* contact) - { - b2Assert(m_contactCount < m_contactCapacity); - m_contacts[m_contactCount++] = contact; - } - - void Add(b2Joint* joint) - { - b2Assert(m_jointCount < m_jointCapacity); - m_joints[m_jointCount++] = joint; - } - - void Report(const b2ContactVelocityConstraint* constraints); - - b2StackAllocator* m_allocator; - b2ContactListener* m_listener; - - b2Body** m_bodies; - b2Contact** m_contacts; - b2Joint** m_joints; - - b2Position* m_positions; - b2Velocity* m_velocities; - - int32 m_bodyCount; - int32 m_jointCount; - int32 m_contactCount; - - int32 m_bodyCapacity; - int32 m_contactCapacity; - int32 m_jointCapacity; -}; - -#endif diff --git a/external/Box2D/Dynamics/b2TimeStep.h b/external/Box2D/Dynamics/b2TimeStep.h deleted file mode 100644 index 30d723fcc3..0000000000 --- a/external/Box2D/Dynamics/b2TimeStep.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_TIME_STEP_H -#define B2_TIME_STEP_H - -#include - -/// Profiling data. Times are in milliseconds. -struct b2Profile -{ - float32 step; - float32 collide; - float32 solve; - float32 solveInit; - float32 solveVelocity; - float32 solvePosition; - float32 broadphase; - float32 solveTOI; -}; - -/// This is an internal structure. -struct b2TimeStep -{ - float32 dt; // time step - float32 inv_dt; // inverse time step (0 if dt == 0). - float32 dtRatio; // dt * inv_dt0 - int32 velocityIterations; - int32 positionIterations; - bool warmStarting; -}; - -/// This is an internal structure. -struct b2Position -{ - b2Vec2 c; - float32 a; -}; - -/// This is an internal structure. -struct b2Velocity -{ - b2Vec2 v; - float32 w; -}; - -/// Solver Data -struct b2SolverData -{ - b2TimeStep step; - b2Position* positions; - b2Velocity* velocities; -}; - -#endif diff --git a/external/Box2D/Dynamics/b2World.cpp b/external/Box2D/Dynamics/b2World.cpp deleted file mode 100644 index 8a0aff5114..0000000000 --- a/external/Box2D/Dynamics/b2World.cpp +++ /dev/null @@ -1,1316 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -b2World::b2World(const b2Vec2& gravity) -{ - m_destructionListener = NULL; - m_debugDraw = NULL; - - m_bodyList = NULL; - m_jointList = NULL; - - m_bodyCount = 0; - m_jointCount = 0; - - m_warmStarting = true; - m_continuousPhysics = true; - m_subStepping = false; - - m_stepComplete = true; - - m_allowSleep = true; - m_gravity = gravity; - - m_flags = e_clearForces; - - m_inv_dt0 = 0.0f; - - m_contactManager.m_allocator = &m_blockAllocator; - - memset(&m_profile, 0, sizeof(b2Profile)); -} - -b2World::~b2World() -{ - // Some shapes allocate using b2Alloc. - b2Body* b = m_bodyList; - while (b) - { - b2Body* bNext = b->m_next; - - b2Fixture* f = b->m_fixtureList; - while (f) - { - b2Fixture* fNext = f->m_next; - f->m_proxyCount = 0; - f->Destroy(&m_blockAllocator); - f = fNext; - } - - b = bNext; - } -} - -void b2World::SetDestructionListener(b2DestructionListener* listener) -{ - m_destructionListener = listener; -} - -void b2World::SetContactFilter(b2ContactFilter* filter) -{ - m_contactManager.m_contactFilter = filter; -} - -void b2World::SetContactListener(b2ContactListener* listener) -{ - m_contactManager.m_contactListener = listener; -} - -void b2World::SetDebugDraw(b2Draw* debugDraw) -{ - m_debugDraw = debugDraw; -} - -b2Body* b2World::CreateBody(const b2BodyDef* def) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return NULL; - } - - void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); - b2Body* b = new (mem) b2Body(def, this); - - // Add to world doubly linked list. - b->m_prev = NULL; - b->m_next = m_bodyList; - if (m_bodyList) - { - m_bodyList->m_prev = b; - } - m_bodyList = b; - ++m_bodyCount; - - return b; -} - -void b2World::DestroyBody(b2Body* b) -{ - b2Assert(m_bodyCount > 0); - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return; - } - - // Delete the attached joints. - b2JointEdge* je = b->m_jointList; - while (je) - { - b2JointEdge* je0 = je; - je = je->next; - - if (m_destructionListener) - { - m_destructionListener->SayGoodbye(je0->joint); - } - - DestroyJoint(je0->joint); - - b->m_jointList = je; - } - b->m_jointList = NULL; - - // Delete the attached contacts. - b2ContactEdge* ce = b->m_contactList; - while (ce) - { - b2ContactEdge* ce0 = ce; - ce = ce->next; - m_contactManager.Destroy(ce0->contact); - } - b->m_contactList = NULL; - - // Delete the attached fixtures. This destroys broad-phase proxies. - b2Fixture* f = b->m_fixtureList; - while (f) - { - b2Fixture* f0 = f; - f = f->m_next; - - if (m_destructionListener) - { - m_destructionListener->SayGoodbye(f0); - } - - f0->DestroyProxies(&m_contactManager.m_broadPhase); - f0->Destroy(&m_blockAllocator); - f0->~b2Fixture(); - m_blockAllocator.Free(f0, sizeof(b2Fixture)); - - b->m_fixtureList = f; - b->m_fixtureCount -= 1; - } - b->m_fixtureList = NULL; - b->m_fixtureCount = 0; - - // Remove world body list. - if (b->m_prev) - { - b->m_prev->m_next = b->m_next; - } - - if (b->m_next) - { - b->m_next->m_prev = b->m_prev; - } - - if (b == m_bodyList) - { - m_bodyList = b->m_next; - } - - --m_bodyCount; - b->~b2Body(); - m_blockAllocator.Free(b, sizeof(b2Body)); -} - -b2Joint* b2World::CreateJoint(const b2JointDef* def) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return NULL; - } - - b2Joint* j = b2Joint::Create(def, &m_blockAllocator); - - // Connect to the world list. - j->m_prev = NULL; - j->m_next = m_jointList; - if (m_jointList) - { - m_jointList->m_prev = j; - } - m_jointList = j; - ++m_jointCount; - - // Connect to the bodies' doubly linked lists. - j->m_edgeA.joint = j; - j->m_edgeA.other = j->m_bodyB; - j->m_edgeA.prev = NULL; - j->m_edgeA.next = j->m_bodyA->m_jointList; - if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; - j->m_bodyA->m_jointList = &j->m_edgeA; - - j->m_edgeB.joint = j; - j->m_edgeB.other = j->m_bodyA; - j->m_edgeB.prev = NULL; - j->m_edgeB.next = j->m_bodyB->m_jointList; - if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; - j->m_bodyB->m_jointList = &j->m_edgeB; - - b2Body* bodyA = def->bodyA; - b2Body* bodyB = def->bodyB; - - // If the joint prevents collisions, then flag any contacts for filtering. - if (def->collideConnected == false) - { - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - // Flag the contact for filtering at the next time step (where either - // body is awake). - edge->contact->FlagForFiltering(); - } - - edge = edge->next; - } - } - - // Note: creating a joint doesn't wake the bodies. - - return j; -} - -void b2World::DestroyJoint(b2Joint* j) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return; - } - - bool collideConnected = j->m_collideConnected; - - // Remove from the doubly linked list. - if (j->m_prev) - { - j->m_prev->m_next = j->m_next; - } - - if (j->m_next) - { - j->m_next->m_prev = j->m_prev; - } - - if (j == m_jointList) - { - m_jointList = j->m_next; - } - - // Disconnect from island graph. - b2Body* bodyA = j->m_bodyA; - b2Body* bodyB = j->m_bodyB; - - // Wake up connected bodies. - bodyA->SetAwake(true); - bodyB->SetAwake(true); - - // Remove from body 1. - if (j->m_edgeA.prev) - { - j->m_edgeA.prev->next = j->m_edgeA.next; - } - - if (j->m_edgeA.next) - { - j->m_edgeA.next->prev = j->m_edgeA.prev; - } - - if (&j->m_edgeA == bodyA->m_jointList) - { - bodyA->m_jointList = j->m_edgeA.next; - } - - j->m_edgeA.prev = NULL; - j->m_edgeA.next = NULL; - - // Remove from body 2 - if (j->m_edgeB.prev) - { - j->m_edgeB.prev->next = j->m_edgeB.next; - } - - if (j->m_edgeB.next) - { - j->m_edgeB.next->prev = j->m_edgeB.prev; - } - - if (&j->m_edgeB == bodyB->m_jointList) - { - bodyB->m_jointList = j->m_edgeB.next; - } - - j->m_edgeB.prev = NULL; - j->m_edgeB.next = NULL; - - b2Joint::Destroy(j, &m_blockAllocator); - - b2Assert(m_jointCount > 0); - --m_jointCount; - - // If the joint prevents collisions, then flag any contacts for filtering. - if (collideConnected == false) - { - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - // Flag the contact for filtering at the next time step (where either - // body is awake). - edge->contact->FlagForFiltering(); - } - - edge = edge->next; - } - } -} - -// -void b2World::SetAllowSleeping(bool flag) -{ - if (flag == m_allowSleep) - { - return; - } - - m_allowSleep = flag; - if (m_allowSleep == false) - { - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->SetAwake(true); - } - } -} - -// Find islands, integrate and solve constraints, solve position constraints -void b2World::Solve(const b2TimeStep& step) -{ - m_profile.solveInit = 0.0f; - m_profile.solveVelocity = 0.0f; - m_profile.solvePosition = 0.0f; - - // Size the island for the worst case. - b2Island island(m_bodyCount, - m_contactManager.m_contactCount, - m_jointCount, - &m_stackAllocator, - m_contactManager.m_contactListener); - - // Clear all the island flags. - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_flags &= ~b2Body::e_islandFlag; - } - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - c->m_flags &= ~b2Contact::e_islandFlag; - } - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - j->m_islandFlag = false; - } - - // Build and simulate all awake islands. - int32 stackSize = m_bodyCount; - b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); - for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) - { - if (seed->m_flags & b2Body::e_islandFlag) - { - continue; - } - - if (seed->IsAwake() == false || seed->IsActive() == false) - { - continue; - } - - // The seed can be dynamic or kinematic. - if (seed->GetType() == b2_staticBody) - { - continue; - } - - // Reset island and stack. - island.Clear(); - int32 stackCount = 0; - stack[stackCount++] = seed; - seed->m_flags |= b2Body::e_islandFlag; - - // Perform a depth first search (DFS) on the constraint graph. - while (stackCount > 0) - { - // Grab the next body off the stack and add it to the island. - b2Body* b = stack[--stackCount]; - b2Assert(b->IsActive() == true); - island.Add(b); - - // Make sure the body is awake. - b->SetAwake(true); - - // To keep islands as small as possible, we don't - // propagate islands across static bodies. - if (b->GetType() == b2_staticBody) - { - continue; - } - - // Search all contacts connected to this body. - for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) - { - b2Contact* contact = ce->contact; - - // Has this contact already been added to an island? - if (contact->m_flags & b2Contact::e_islandFlag) - { - continue; - } - - // Is this contact solid and touching? - if (contact->IsEnabled() == false || - contact->IsTouching() == false) - { - continue; - } - - // Skip sensors. - bool sensorA = contact->m_fixtureA->m_isSensor; - bool sensorB = contact->m_fixtureB->m_isSensor; - if (sensorA || sensorB) - { - continue; - } - - island.Add(contact); - contact->m_flags |= b2Contact::e_islandFlag; - - b2Body* other = ce->other; - - // Was the other body already added to this island? - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - b2Assert(stackCount < stackSize); - stack[stackCount++] = other; - other->m_flags |= b2Body::e_islandFlag; - } - - // Search all joints connect to this body. - for (b2JointEdge* je = b->m_jointList; je; je = je->next) - { - if (je->joint->m_islandFlag == true) - { - continue; - } - - b2Body* other = je->other; - - // Don't simulate joints connected to inactive bodies. - if (other->IsActive() == false) - { - continue; - } - - island.Add(je->joint); - je->joint->m_islandFlag = true; - - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - b2Assert(stackCount < stackSize); - stack[stackCount++] = other; - other->m_flags |= b2Body::e_islandFlag; - } - } - - b2Profile profile; - island.Solve(&profile, step, m_gravity, m_allowSleep); - m_profile.solveInit += profile.solveInit; - m_profile.solveVelocity += profile.solveVelocity; - m_profile.solvePosition += profile.solvePosition; - - // Post solve cleanup. - for (int32 i = 0; i < island.m_bodyCount; ++i) - { - // Allow static bodies to participate in other islands. - b2Body* b = island.m_bodies[i]; - if (b->GetType() == b2_staticBody) - { - b->m_flags &= ~b2Body::e_islandFlag; - } - } - } - - m_stackAllocator.Free(stack); - - { - b2Timer timer; - // Synchronize fixtures, check for out of range bodies. - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - // If a body was not in an island then it did not move. - if ((b->m_flags & b2Body::e_islandFlag) == 0) - { - continue; - } - - if (b->GetType() == b2_staticBody) - { - continue; - } - - // Update fixtures (for broad-phase). - b->SynchronizeFixtures(); - } - - // Look for new contacts. - m_contactManager.FindNewContacts(); - m_profile.broadphase = timer.GetMilliseconds(); - } -} - -// Find TOI contacts and solve them. -void b2World::SolveTOI(const b2TimeStep& step) -{ - b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); - - if (m_stepComplete) - { - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_flags &= ~b2Body::e_islandFlag; - b->m_sweep.alpha0 = 0.0f; - } - - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - // Invalidate TOI - c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); - c->m_toiCount = 0; - c->m_toi = 1.0f; - } - } - - // Find TOI events and solve them. - for (;;) - { - // Find the first TOI. - b2Contact* minContact = NULL; - float32 minAlpha = 1.0f; - - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - // Is this contact disabled? - if (c->IsEnabled() == false) - { - continue; - } - - // Prevent excessive sub-stepping. - if (c->m_toiCount > b2_maxSubSteps) - { - continue; - } - - float32 alpha = 1.0f; - if (c->m_flags & b2Contact::e_toiFlag) - { - // This contact has a valid cached TOI. - alpha = c->m_toi; - } - else - { - b2Fixture* fA = c->GetFixtureA(); - b2Fixture* fB = c->GetFixtureB(); - - // Is there a sensor? - if (fA->IsSensor() || fB->IsSensor()) - { - continue; - } - - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - b2BodyType typeA = bA->m_type; - b2BodyType typeB = bB->m_type; - b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); - - bool activeA = bA->IsAwake() && typeA != b2_staticBody; - bool activeB = bB->IsAwake() && typeB != b2_staticBody; - - // Is at least one body active (awake and dynamic or kinematic)? - if (activeA == false && activeB == false) - { - continue; - } - - bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; - bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; - - // Are these two non-bullet dynamic bodies? - if (collideA == false && collideB == false) - { - continue; - } - - // Compute the TOI for this contact. - // Put the sweeps onto the same time interval. - float32 alpha0 = bA->m_sweep.alpha0; - - if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) - { - alpha0 = bB->m_sweep.alpha0; - bA->m_sweep.Advance(alpha0); - } - else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) - { - alpha0 = bA->m_sweep.alpha0; - bB->m_sweep.Advance(alpha0); - } - - b2Assert(alpha0 < 1.0f); - - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - - // Compute the time of impact in interval [0, minTOI] - b2TOIInput input; - input.proxyA.Set(fA->GetShape(), indexA); - input.proxyB.Set(fB->GetShape(), indexB); - input.sweepA = bA->m_sweep; - input.sweepB = bB->m_sweep; - input.tMax = 1.0f; - - b2TOIOutput output; - b2TimeOfImpact(&output, &input); - - // Beta is the fraction of the remaining portion of the . - float32 beta = output.t; - if (output.state == b2TOIOutput::e_touching) - { - alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); - } - else - { - alpha = 1.0f; - } - - c->m_toi = alpha; - c->m_flags |= b2Contact::e_toiFlag; - } - - if (alpha < minAlpha) - { - // This is the minimum TOI found so far. - minContact = c; - minAlpha = alpha; - } - } - - if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) - { - // No more TOI events. Done! - m_stepComplete = true; - break; - } - - // Advance the bodies to the TOI. - b2Fixture* fA = minContact->GetFixtureA(); - b2Fixture* fB = minContact->GetFixtureB(); - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - b2Sweep backup1 = bA->m_sweep; - b2Sweep backup2 = bB->m_sweep; - - bA->Advance(minAlpha); - bB->Advance(minAlpha); - - // The TOI contact likely has some new contact points. - minContact->Update(m_contactManager.m_contactListener); - minContact->m_flags &= ~b2Contact::e_toiFlag; - ++minContact->m_toiCount; - - // Is the contact solid? - if (minContact->IsEnabled() == false || minContact->IsTouching() == false) - { - // Restore the sweeps. - minContact->SetEnabled(false); - bA->m_sweep = backup1; - bB->m_sweep = backup2; - bA->SynchronizeTransform(); - bB->SynchronizeTransform(); - continue; - } - - bA->SetAwake(true); - bB->SetAwake(true); - - // Build the island - island.Clear(); - island.Add(bA); - island.Add(bB); - island.Add(minContact); - - bA->m_flags |= b2Body::e_islandFlag; - bB->m_flags |= b2Body::e_islandFlag; - minContact->m_flags |= b2Contact::e_islandFlag; - - // Get contacts on bodyA and bodyB. - b2Body* bodies[2] = {bA, bB}; - for (int32 i = 0; i < 2; ++i) - { - b2Body* body = bodies[i]; - if (body->m_type == b2_dynamicBody) - { - for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) - { - if (island.m_bodyCount == island.m_bodyCapacity) - { - break; - } - - if (island.m_contactCount == island.m_contactCapacity) - { - break; - } - - b2Contact* contact = ce->contact; - - // Has this contact already been added to the island? - if (contact->m_flags & b2Contact::e_islandFlag) - { - continue; - } - - // Only add static, kinematic, or bullet bodies. - b2Body* other = ce->other; - if (other->m_type == b2_dynamicBody && - body->IsBullet() == false && other->IsBullet() == false) - { - continue; - } - - // Skip sensors. - bool sensorA = contact->m_fixtureA->m_isSensor; - bool sensorB = contact->m_fixtureB->m_isSensor; - if (sensorA || sensorB) - { - continue; - } - - // Tentatively advance the body to the TOI. - b2Sweep backup = other->m_sweep; - if ((other->m_flags & b2Body::e_islandFlag) == 0) - { - other->Advance(minAlpha); - } - - // Update the contact points - contact->Update(m_contactManager.m_contactListener); - - // Was the contact disabled by the user? - if (contact->IsEnabled() == false) - { - other->m_sweep = backup; - other->SynchronizeTransform(); - continue; - } - - // Are there contact points? - if (contact->IsTouching() == false) - { - other->m_sweep = backup; - other->SynchronizeTransform(); - continue; - } - - // Add the contact to the island - contact->m_flags |= b2Contact::e_islandFlag; - island.Add(contact); - - // Has the other body already been added to the island? - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - // Add the other body to the island. - other->m_flags |= b2Body::e_islandFlag; - - if (other->m_type != b2_staticBody) - { - other->SetAwake(true); - } - - island.Add(other); - } - } - } - - b2TimeStep subStep; - subStep.dt = (1.0f - minAlpha) * step.dt; - subStep.inv_dt = 1.0f / subStep.dt; - subStep.dtRatio = 1.0f; - subStep.positionIterations = 20; - subStep.velocityIterations = step.velocityIterations; - subStep.warmStarting = false; - island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); - - // Reset island flags and synchronize broad-phase proxies. - for (int32 i = 0; i < island.m_bodyCount; ++i) - { - b2Body* body = island.m_bodies[i]; - body->m_flags &= ~b2Body::e_islandFlag; - - if (body->m_type != b2_dynamicBody) - { - continue; - } - - body->SynchronizeFixtures(); - - // Invalidate all contact TOIs on this displaced body. - for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) - { - ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); - } - } - - // Commit fixture proxy movements to the broad-phase so that new contacts are created. - // Also, some contacts can be destroyed. - m_contactManager.FindNewContacts(); - - if (m_subStepping) - { - m_stepComplete = false; - break; - } - } -} - -void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) -{ - b2Timer stepTimer; - - // If new fixtures were added, we need to find the new contacts. - if (m_flags & e_newFixture) - { - m_contactManager.FindNewContacts(); - m_flags &= ~e_newFixture; - } - - m_flags |= e_locked; - - b2TimeStep step; - step.dt = dt; - step.velocityIterations = velocityIterations; - step.positionIterations = positionIterations; - if (dt > 0.0f) - { - step.inv_dt = 1.0f / dt; - } - else - { - step.inv_dt = 0.0f; - } - - step.dtRatio = m_inv_dt0 * dt; - - step.warmStarting = m_warmStarting; - - // Update contacts. This is where some contacts are destroyed. - { - b2Timer timer; - m_contactManager.Collide(); - m_profile.collide = timer.GetMilliseconds(); - } - - // Integrate velocities, solve velocity constraints, and integrate positions. - if (m_stepComplete && step.dt > 0.0f) - { - b2Timer timer; - Solve(step); - m_profile.solve = timer.GetMilliseconds(); - } - - // Handle TOI events. - if (m_continuousPhysics && step.dt > 0.0f) - { - b2Timer timer; - SolveTOI(step); - m_profile.solveTOI = timer.GetMilliseconds(); - } - - if (step.dt > 0.0f) - { - m_inv_dt0 = step.inv_dt; - } - - if (m_flags & e_clearForces) - { - ClearForces(); - } - - m_flags &= ~e_locked; - - m_profile.step = stepTimer.GetMilliseconds(); -} - -void b2World::ClearForces() -{ - for (b2Body* body = m_bodyList; body; body = body->GetNext()) - { - body->m_force.SetZero(); - body->m_torque = 0.0f; - } -} - -struct b2WorldQueryWrapper -{ - bool QueryCallback(int32 proxyId) - { - b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); - return callback->ReportFixture(proxy->fixture); - } - - const b2BroadPhase* broadPhase; - b2QueryCallback* callback; -}; - -void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const -{ - b2WorldQueryWrapper wrapper; - wrapper.broadPhase = &m_contactManager.m_broadPhase; - wrapper.callback = callback; - m_contactManager.m_broadPhase.Query(&wrapper, aabb); -} - -struct b2WorldRayCastWrapper -{ - float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) - { - void* userData = broadPhase->GetUserData(proxyId); - b2FixtureProxy* proxy = (b2FixtureProxy*)userData; - b2Fixture* fixture = proxy->fixture; - int32 index = proxy->childIndex; - b2RayCastOutput output; - bool hit = fixture->RayCast(&output, input, index); - - if (hit) - { - float32 fraction = output.fraction; - b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; - return callback->ReportFixture(fixture, point, output.normal, fraction); - } - - return input.maxFraction; - } - - const b2BroadPhase* broadPhase; - b2RayCastCallback* callback; -}; - -void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const -{ - b2WorldRayCastWrapper wrapper; - wrapper.broadPhase = &m_contactManager.m_broadPhase; - wrapper.callback = callback; - b2RayCastInput input; - input.maxFraction = 1.0f; - input.p1 = point1; - input.p2 = point2; - m_contactManager.m_broadPhase.RayCast(&wrapper, input); -} - -void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) -{ - switch (fixture->GetType()) - { - case b2Shape::e_circle: - { - b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); - - b2Vec2 center = b2Mul(xf, circle->m_p); - float32 radius = circle->m_radius; - b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); - - m_debugDraw->DrawSolidCircle(center, radius, axis, color); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); - b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); - b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); - m_debugDraw->DrawSegment(v1, v2, color); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); - int32 count = chain->m_count; - const b2Vec2* vertices = chain->m_vertices; - - b2Vec2 v1 = b2Mul(xf, vertices[0]); - for (int32 i = 1; i < count; ++i) - { - b2Vec2 v2 = b2Mul(xf, vertices[i]); - m_debugDraw->DrawSegment(v1, v2, color); - m_debugDraw->DrawCircle(v1, 0.05f, color); - v1 = v2; - } - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); - int32 vertexCount = poly->m_vertexCount; - b2Assert(vertexCount <= b2_maxPolygonVertices); - b2Vec2 vertices[b2_maxPolygonVertices]; - - for (int32 i = 0; i < vertexCount; ++i) - { - vertices[i] = b2Mul(xf, poly->m_vertices[i]); - } - - m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); - } - break; - - default: - break; - } -} - -void b2World::DrawJoint(b2Joint* joint) -{ - b2Body* bodyA = joint->GetBodyA(); - b2Body* bodyB = joint->GetBodyB(); - const b2Transform& xf1 = bodyA->GetTransform(); - const b2Transform& xf2 = bodyB->GetTransform(); - b2Vec2 x1 = xf1.p; - b2Vec2 x2 = xf2.p; - b2Vec2 p1 = joint->GetAnchorA(); - b2Vec2 p2 = joint->GetAnchorB(); - - b2Color color(0.5f, 0.8f, 0.8f); - - switch (joint->GetType()) - { - case e_distanceJoint: - m_debugDraw->DrawSegment(p1, p2, color); - break; - - case e_pulleyJoint: - { - b2PulleyJoint* pulley = (b2PulleyJoint*)joint; - b2Vec2 s1 = pulley->GetGroundAnchorA(); - b2Vec2 s2 = pulley->GetGroundAnchorB(); - m_debugDraw->DrawSegment(s1, p1, color); - m_debugDraw->DrawSegment(s2, p2, color); - m_debugDraw->DrawSegment(s1, s2, color); - } - break; - - case e_mouseJoint: - // don't draw this - break; - - default: - m_debugDraw->DrawSegment(x1, p1, color); - m_debugDraw->DrawSegment(p1, p2, color); - m_debugDraw->DrawSegment(x2, p2, color); - } -} - -void b2World::DrawDebugData() -{ - if (m_debugDraw == NULL) - { - return; - } - - uint32 flags = m_debugDraw->GetFlags(); - - if (flags & b2Draw::e_shapeBit) - { - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - const b2Transform& xf = b->GetTransform(); - for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) - { - if (b->IsActive() == false) - { - DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); - } - else if (b->GetType() == b2_staticBody) - { - DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); - } - else if (b->GetType() == b2_kinematicBody) - { - DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); - } - else if (b->IsAwake() == false) - { - DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); - } - else - { - DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); - } - } - } - } - - if (flags & b2Draw::e_jointBit) - { - for (b2Joint* j = m_jointList; j; j = j->GetNext()) - { - DrawJoint(j); - } - } - - if (flags & b2Draw::e_pairBit) - { - b2Color color(0.3f, 0.9f, 0.9f); - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) - { - //b2Fixture* fixtureA = c->GetFixtureA(); - //b2Fixture* fixtureB = c->GetFixtureB(); - - //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); - //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); - - //m_debugDraw->DrawSegment(cA, cB, color); - } - } - - if (flags & b2Draw::e_aabbBit) - { - b2Color color(0.9f, 0.3f, 0.9f); - b2BroadPhase* bp = &m_contactManager.m_broadPhase; - - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - if (b->IsActive() == false) - { - continue; - } - - for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) - { - for (int32 i = 0; i < f->m_proxyCount; ++i) - { - b2FixtureProxy* proxy = f->m_proxies + i; - b2AABB aabb = bp->GetFatAABB(proxy->proxyId); - b2Vec2 vs[4]; - vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); - vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); - vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); - vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); - - m_debugDraw->DrawPolygon(vs, 4, color); - } - } - } - } - - if (flags & b2Draw::e_centerOfMassBit) - { - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - b2Transform xf = b->GetTransform(); - xf.p = b->GetWorldCenter(); - m_debugDraw->DrawTransform(xf); - } - } -} - -int32 b2World::GetProxyCount() const -{ - return m_contactManager.m_broadPhase.GetProxyCount(); -} - -int32 b2World::GetTreeHeight() const -{ - return m_contactManager.m_broadPhase.GetTreeHeight(); -} - -int32 b2World::GetTreeBalance() const -{ - return m_contactManager.m_broadPhase.GetTreeBalance(); -} - -float32 b2World::GetTreeQuality() const -{ - return m_contactManager.m_broadPhase.GetTreeQuality(); -} - -void b2World::Dump() -{ - if ((m_flags & e_locked) == e_locked) - { - return; - } - - b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); - b2Log("m_world->SetGravity(g);\n"); - - b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); - b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); - int32 i = 0; - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_islandIndex = i; - b->Dump(); - ++i; - } - - i = 0; - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - j->m_index = i; - ++i; - } - - // First pass on joints, skip gear joints. - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - if (j->m_type == e_gearJoint) - { - continue; - } - - b2Log("{\n"); - j->Dump(); - b2Log("}\n"); - } - - // Second pass on joints, only gear joints. - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - if (j->m_type != e_gearJoint) - { - continue; - } - - b2Log("{\n"); - j->Dump(); - b2Log("}\n"); - } - - b2Log("b2Free(joints);\n"); - b2Log("b2Free(bodies);\n"); - b2Log("joints = NULL;\n"); - b2Log("bodies = NULL;\n"); -} diff --git a/external/Box2D/Dynamics/b2World.h b/external/Box2D/Dynamics/b2World.h deleted file mode 100644 index f207930511..0000000000 --- a/external/Box2D/Dynamics/b2World.h +++ /dev/null @@ -1,349 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WORLD_H -#define B2_WORLD_H - -#include -#include -#include -#include -#include -#include - -struct b2AABB; -struct b2BodyDef; -struct b2Color; -struct b2JointDef; -class b2Body; -class b2Draw; -class b2Fixture; -class b2Joint; - -/// The world class manages all physics entities, dynamic simulation, -/// and asynchronous queries. The world also contains efficient memory -/// management facilities. -class b2World -{ -public: - /// Construct a world object. - /// @param gravity the world gravity vector. - b2World(const b2Vec2& gravity); - - /// Destruct the world. All physics entities are destroyed and all heap memory is released. - ~b2World(); - - /// Register a destruction listener. The listener is owned by you and must - /// remain in scope. - void SetDestructionListener(b2DestructionListener* listener); - - /// Register a contact filter to provide specific control over collision. - /// Otherwise the default filter is used (b2_defaultFilter). The listener is - /// owned by you and must remain in scope. - void SetContactFilter(b2ContactFilter* filter); - - /// Register a contact event listener. The listener is owned by you and must - /// remain in scope. - void SetContactListener(b2ContactListener* listener); - - /// Register a routine for debug drawing. The debug draw functions are called - /// inside with b2World::DrawDebugData method. The debug draw object is owned - /// by you and must remain in scope. - void SetDebugDraw(b2Draw* debugDraw); - - /// Create a rigid body given a definition. No reference to the definition - /// is retained. - /// @warning This function is locked during callbacks. - b2Body* CreateBody(const b2BodyDef* def); - - /// Destroy a rigid body given a definition. No reference to the definition - /// is retained. This function is locked during callbacks. - /// @warning This automatically deletes all associated shapes and joints. - /// @warning This function is locked during callbacks. - void DestroyBody(b2Body* body); - - /// Create a joint to constrain bodies together. No reference to the definition - /// is retained. This may cause the connected bodies to cease colliding. - /// @warning This function is locked during callbacks. - b2Joint* CreateJoint(const b2JointDef* def); - - /// Destroy a joint. This may cause the connected bodies to begin colliding. - /// @warning This function is locked during callbacks. - void DestroyJoint(b2Joint* joint); - - /// Take a time step. This performs collision detection, integration, - /// and constraint solution. - /// @param timeStep the amount of time to simulate, this should not vary. - /// @param velocityIterations for the velocity constraint solver. - /// @param positionIterations for the position constraint solver. - void Step( float32 timeStep, - int32 velocityIterations, - int32 positionIterations); - - /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically - /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. - /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain - /// a fixed sized time step under a variable frame-rate. - /// When you perform sub-stepping you will disable auto clearing of forces and instead call - /// ClearForces after all sub-steps are complete in one pass of your game loop. - /// @see SetAutoClearForces - void ClearForces(); - - /// Call this to draw shapes and other debug draw data. - void DrawDebugData(); - - /// Query the world for all fixtures that potentially overlap the - /// provided AABB. - /// @param callback a user implemented callback class. - /// @param aabb the query box. - void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; - - /// Ray-cast the world for all fixtures in the path of the ray. Your callback - /// controls whether you get the closest point, any point, or n-points. - /// The ray-cast ignores shapes that contain the starting point. - /// @param callback a user implemented callback class. - /// @param point1 the ray starting point - /// @param point2 the ray ending point - void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; - - /// Get the world body list. With the returned body, use b2Body::GetNext to get - /// the next body in the world list. A NULL body indicates the end of the list. - /// @return the head of the world body list. - b2Body* GetBodyList(); - const b2Body* GetBodyList() const; - - /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get - /// the next joint in the world list. A NULL joint indicates the end of the list. - /// @return the head of the world joint list. - b2Joint* GetJointList(); - const b2Joint* GetJointList() const; - - /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get - /// the next contact in the world list. A NULL contact indicates the end of the list. - /// @return the head of the world contact list. - /// @warning contacts are created and destroyed in the middle of a time step. - /// Use b2ContactListener to avoid missing contacts. - b2Contact* GetContactList(); - const b2Contact* GetContactList() const; - - /// Enable/disable sleep. - void SetAllowSleeping(bool flag); - bool GetAllowSleeping() const { return m_allowSleep; } - - /// Enable/disable warm starting. For testing. - void SetWarmStarting(bool flag) { m_warmStarting = flag; } - bool GetWarmStarting() const { return m_warmStarting; } - - /// Enable/disable continuous physics. For testing. - void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } - bool GetContinuousPhysics() const { return m_continuousPhysics; } - - /// Enable/disable single stepped continuous physics. For testing. - void SetSubStepping(bool flag) { m_subStepping = flag; } - bool GetSubStepping() const { return m_subStepping; } - - /// Get the number of broad-phase proxies. - int32 GetProxyCount() const; - - /// Get the number of bodies. - int32 GetBodyCount() const; - - /// Get the number of joints. - int32 GetJointCount() const; - - /// Get the number of contacts (each may have 0 or more contact points). - int32 GetContactCount() const; - - /// Get the height of the dynamic tree. - int32 GetTreeHeight() const; - - /// Get the balance of the dynamic tree. - int32 GetTreeBalance() const; - - /// Get the quality metric of the dynamic tree. The smaller the better. - /// The minimum is 1. - float32 GetTreeQuality() const; - - /// Change the global gravity vector. - void SetGravity(const b2Vec2& gravity); - - /// Get the global gravity vector. - b2Vec2 GetGravity() const; - - /// Is the world locked (in the middle of a time step). - bool IsLocked() const; - - /// Set flag to control automatic clearing of forces after each time step. - void SetAutoClearForces(bool flag); - - /// Get the flag that controls automatic clearing of forces after each time step. - bool GetAutoClearForces() const; - - /// Get the contact manager for testing. - const b2ContactManager& GetContactManager() const; - - /// Get the current profile. - const b2Profile& GetProfile() const; - - /// Dump the world into the log file. - /// @warning this should be called outside of a time step. - void Dump(); - -private: - - // m_flags - enum - { - e_newFixture = 0x0001, - e_locked = 0x0002, - e_clearForces = 0x0004 - }; - - friend class b2Body; - friend class b2Fixture; - friend class b2ContactManager; - friend class b2Controller; - - void Solve(const b2TimeStep& step); - void SolveTOI(const b2TimeStep& step); - - void DrawJoint(b2Joint* joint); - void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); - - b2BlockAllocator m_blockAllocator; - b2StackAllocator m_stackAllocator; - - int32 m_flags; - - b2ContactManager m_contactManager; - - b2Body* m_bodyList; - b2Joint* m_jointList; - - int32 m_bodyCount; - int32 m_jointCount; - - b2Vec2 m_gravity; - bool m_allowSleep; - - b2DestructionListener* m_destructionListener; - b2Draw* m_debugDraw; - - // This is used to compute the time step ratio to - // support a variable time step. - float32 m_inv_dt0; - - // These are for debugging the solver. - bool m_warmStarting; - bool m_continuousPhysics; - bool m_subStepping; - - bool m_stepComplete; - - b2Profile m_profile; -}; - -inline b2Body* b2World::GetBodyList() -{ - return m_bodyList; -} - -inline const b2Body* b2World::GetBodyList() const -{ - return m_bodyList; -} - -inline b2Joint* b2World::GetJointList() -{ - return m_jointList; -} - -inline const b2Joint* b2World::GetJointList() const -{ - return m_jointList; -} - -inline b2Contact* b2World::GetContactList() -{ - return m_contactManager.m_contactList; -} - -inline const b2Contact* b2World::GetContactList() const -{ - return m_contactManager.m_contactList; -} - -inline int32 b2World::GetBodyCount() const -{ - return m_bodyCount; -} - -inline int32 b2World::GetJointCount() const -{ - return m_jointCount; -} - -inline int32 b2World::GetContactCount() const -{ - return m_contactManager.m_contactCount; -} - -inline void b2World::SetGravity(const b2Vec2& gravity) -{ - m_gravity = gravity; -} - -inline b2Vec2 b2World::GetGravity() const -{ - return m_gravity; -} - -inline bool b2World::IsLocked() const -{ - return (m_flags & e_locked) == e_locked; -} - -inline void b2World::SetAutoClearForces(bool flag) -{ - if (flag) - { - m_flags |= e_clearForces; - } - else - { - m_flags &= ~e_clearForces; - } -} - -/// Get the flag that controls automatic clearing of forces after each time step. -inline bool b2World::GetAutoClearForces() const -{ - return (m_flags & e_clearForces) == e_clearForces; -} - -inline const b2ContactManager& b2World::GetContactManager() const -{ - return m_contactManager; -} - -inline const b2Profile& b2World::GetProfile() const -{ - return m_profile; -} - -#endif diff --git a/external/Box2D/Dynamics/b2WorldCallbacks.cpp b/external/Box2D/Dynamics/b2WorldCallbacks.cpp deleted file mode 100644 index 48ad0cc46a..0000000000 --- a/external/Box2D/Dynamics/b2WorldCallbacks.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -// Return true if contact calculations should be performed between these two shapes. -// If you implement your own collision filter you may want to build from this implementation. -bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) -{ - const b2Filter& filterA = fixtureA->GetFilterData(); - const b2Filter& filterB = fixtureB->GetFilterData(); - - if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) - { - return filterA.groupIndex > 0; - } - - bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; - return collide; -} diff --git a/external/Box2D/Dynamics/b2WorldCallbacks.h b/external/Box2D/Dynamics/b2WorldCallbacks.h deleted file mode 100644 index 86c04e3e32..0000000000 --- a/external/Box2D/Dynamics/b2WorldCallbacks.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_WORLD_CALLBACKS_H -#define B2_WORLD_CALLBACKS_H - -#include - -struct b2Vec2; -struct b2Transform; -class b2Fixture; -class b2Body; -class b2Joint; -class b2Contact; -struct b2ContactResult; -struct b2Manifold; - -/// Joints and fixtures are destroyed when their associated -/// body is destroyed. Implement this listener so that you -/// may nullify references to these joints and shapes. -class b2DestructionListener -{ -public: - virtual ~b2DestructionListener() {} - - /// Called when any joint is about to be destroyed due - /// to the destruction of one of its attached bodies. - virtual void SayGoodbye(b2Joint* joint) = 0; - - /// Called when any fixture is about to be destroyed due - /// to the destruction of its parent body. - virtual void SayGoodbye(b2Fixture* fixture) = 0; -}; - -/// Implement this class to provide collision filtering. In other words, you can implement -/// this class if you want finer control over contact creation. -class b2ContactFilter -{ -public: - virtual ~b2ContactFilter() {} - - /// Return true if contact calculations should be performed between these two shapes. - /// @warning for performance reasons this is only called when the AABBs begin to overlap. - virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); -}; - -/// Contact impulses for reporting. Impulses are used instead of forces because -/// sub-step forces may approach infinity for rigid body collisions. These -/// match up one-to-one with the contact points in b2Manifold. -struct b2ContactImpulse -{ - float32 normalImpulses[b2_maxManifoldPoints]; - float32 tangentImpulses[b2_maxManifoldPoints]; - int32 count; -}; - -/// Implement this class to get contact information. You can use these results for -/// things like sounds and game logic. You can also get contact results by -/// traversing the contact lists after the time step. However, you might miss -/// some contacts because continuous physics leads to sub-stepping. -/// Additionally you may receive multiple callbacks for the same contact in a -/// single time step. -/// You should strive to make your callbacks efficient because there may be -/// many callbacks per time step. -/// @warning You cannot create/destroy Box2D entities inside these callbacks. -class b2ContactListener -{ -public: - virtual ~b2ContactListener() {} - - /// Called when two fixtures begin to touch. - virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } - - /// Called when two fixtures cease to touch. - virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } - - /// This is called after a contact is updated. This allows you to inspect a - /// contact before it goes to the solver. If you are careful, you can modify the - /// contact manifold (e.g. disable contact). - /// A copy of the old manifold is provided so that you can detect changes. - /// Note: this is called only for awake bodies. - /// Note: this is called even when the number of contact points is zero. - /// Note: this is not called for sensors. - /// Note: if you set the number of contact points to zero, you will not - /// get an EndContact callback. However, you may get a BeginContact callback - /// the next step. - virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) - { - B2_NOT_USED(contact); - B2_NOT_USED(oldManifold); - } - - /// This lets you inspect a contact after the solver is finished. This is useful - /// for inspecting impulses. - /// Note: the contact manifold does not include time of impact impulses, which can be - /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly - /// in a separate data structure. - /// Note: this is only called for contacts that are touching, solid, and awake. - virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) - { - B2_NOT_USED(contact); - B2_NOT_USED(impulse); - } -}; - -/// Callback class for AABB queries. -/// See b2World::Query -class b2QueryCallback -{ -public: - virtual ~b2QueryCallback() {} - - /// Called for each fixture found in the query AABB. - /// @return false to terminate the query. - virtual bool ReportFixture(b2Fixture* fixture) = 0; -}; - -/// Callback class for ray casts. -/// See b2World::RayCast -class b2RayCastCallback -{ -public: - virtual ~b2RayCastCallback() {} - - /// Called for each fixture found in the query. You control how the ray cast - /// proceeds by returning a float: - /// return -1: ignore this fixture and continue - /// return 0: terminate the ray cast - /// return fraction: clip the ray to this point - /// return 1: don't clip the ray and continue - /// @param fixture the fixture hit by the ray - /// @param point the point of initial intersection - /// @param normal the normal vector at the point of intersection - /// @return -1 to filter, 0 to terminate, fraction to clip the ray for - /// closest hit, 1 to continue - virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, - const b2Vec2& normal, float32 fraction) = 0; -}; - -#endif diff --git a/external/Box2D/Rope/b2Rope.cpp b/external/Box2D/Rope/b2Rope.cpp deleted file mode 100644 index 9bf671aec9..0000000000 --- a/external/Box2D/Rope/b2Rope.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 -#include - -b2Rope::b2Rope() -{ - m_count = 0; - m_ps = NULL; - m_p0s = NULL; - m_vs = NULL; - m_ims = NULL; - m_Ls = NULL; - m_as = NULL; - m_gravity.SetZero(); - m_k2 = 1.0f; - m_k3 = 0.1f; -} - -b2Rope::~b2Rope() -{ - b2Free(m_ps); - b2Free(m_p0s); - b2Free(m_vs); - b2Free(m_ims); - b2Free(m_Ls); - b2Free(m_as); -} - -void b2Rope::Initialize(const b2RopeDef* def) -{ - b2Assert(def->count >= 3); - m_count = def->count; - m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_ims = (float32*)b2Alloc(m_count * sizeof(float32)); - - for (int32 i = 0; i < m_count; ++i) - { - m_ps[i] = def->vertices[i]; - m_p0s[i] = def->vertices[i]; - m_vs[i].SetZero(); - - float32 m = def->masses[i]; - if (m > 0.0f) - { - m_ims[i] = 1.0f / m; - } - else - { - m_ims[i] = 0.0f; - } - } - - int32 count2 = m_count - 1; - int32 count3 = m_count - 2; - m_Ls = (float32*)b2Alloc(count2 * sizeof(float32)); - m_as = (float32*)b2Alloc(count3 * sizeof(float32)); - - for (int32 i = 0; i < count2; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i+1]; - m_Ls[i] = b2Distance(p1, p2); - } - - for (int32 i = 0; i < count3; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - b2Vec2 p3 = m_ps[i + 2]; - - b2Vec2 d1 = p2 - p1; - b2Vec2 d2 = p3 - p2; - - float32 a = b2Cross(d1, d2); - float32 b = b2Dot(d1, d2); - - m_as[i] = b2Atan2(a, b); - } - - m_gravity = def->gravity; - m_damping = def->damping; - m_k2 = def->k2; - m_k3 = def->k3; -} - -void b2Rope::Step(float32 h, int32 iterations) -{ - if (h == 0.0) - { - return; - } - - float32 d = expf(- h * m_damping); - - for (int32 i = 0; i < m_count; ++i) - { - m_p0s[i] = m_ps[i]; - if (m_ims[i] > 0.0f) - { - m_vs[i] += h * m_gravity; - } - m_vs[i] *= d; - m_ps[i] += h * m_vs[i]; - - } - - for (int32 i = 0; i < iterations; ++i) - { - SolveC2(); - SolveC3(); - SolveC2(); - } - - float32 inv_h = 1.0f / h; - for (int32 i = 0; i < m_count; ++i) - { - m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]); - } -} - -void b2Rope::SolveC2() -{ - int32 count2 = m_count - 1; - - for (int32 i = 0; i < count2; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - - b2Vec2 d = p2 - p1; - float32 L = d.Normalize(); - - float32 im1 = m_ims[i]; - float32 im2 = m_ims[i + 1]; - - if (im1 + im2 == 0.0f) - { - continue; - } - - float32 s1 = im1 / (im1 + im2); - float32 s2 = im2 / (im1 + im2); - - p1 -= m_k2 * s1 * (m_Ls[i] - L) * d; - p2 += m_k2 * s2 * (m_Ls[i] - L) * d; - - m_ps[i] = p1; - m_ps[i + 1] = p2; - } -} - -void b2Rope::SetAngle(float32 angle) -{ - int32 count3 = m_count - 2; - for (int32 i = 0; i < count3; ++i) - { - m_as[i] = angle; - } -} - -void b2Rope::SolveC3() -{ - int32 count3 = m_count - 2; - - for (int32 i = 0; i < count3; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - b2Vec2 p3 = m_ps[i + 2]; - - float32 m1 = m_ims[i]; - float32 m2 = m_ims[i + 1]; - float32 m3 = m_ims[i + 2]; - - b2Vec2 d1 = p2 - p1; - b2Vec2 d2 = p3 - p2; - - float32 L1sqr = d1.LengthSquared(); - float32 L2sqr = d2.LengthSquared(); - - if (L1sqr * L2sqr == 0.0f) - { - continue; - } - - float32 a = b2Cross(d1, d2); - float32 b = b2Dot(d1, d2); - - float32 angle = b2Atan2(a, b); - - b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew(); - b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew(); - - b2Vec2 J1 = -Jd1; - b2Vec2 J2 = Jd1 - Jd2; - b2Vec2 J3 = Jd2; - - float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3); - if (mass == 0.0f) - { - continue; - } - - mass = 1.0f / mass; - - float32 C = angle - m_as[i]; - - while (C > b2_pi) - { - angle -= 2 * b2_pi; - C = angle - m_as[i]; - } - - while (C < -b2_pi) - { - angle += 2.0f * b2_pi; - C = angle - m_as[i]; - } - - float32 impulse = - m_k3 * mass * C; - - p1 += (m1 * impulse) * J1; - p2 += (m2 * impulse) * J2; - p3 += (m3 * impulse) * J3; - - m_ps[i] = p1; - m_ps[i + 1] = p2; - m_ps[i + 2] = p3; - } -} - -void b2Rope::Draw(b2Draw* draw) const -{ - b2Color c(0.4f, 0.5f, 0.7f); - - for (int32 i = 0; i < m_count - 1; ++i) - { - draw->DrawSegment(m_ps[i], m_ps[i+1], c); - } -} diff --git a/external/Box2D/Rope/b2Rope.h b/external/Box2D/Rope/b2Rope.h deleted file mode 100644 index b981dfd6c5..0000000000 --- a/external/Box2D/Rope/b2Rope.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef B2_ROPE_H -#define B2_ROPE_H - -#include - -class b2Draw; - -/// -struct b2RopeDef -{ - b2RopeDef() - { - vertices = NULL; - count = 0; - masses = NULL; - gravity.SetZero(); - damping = 0.1f; - k2 = 0.9f; - k3 = 0.1f; - } - - /// - b2Vec2* vertices; - - /// - int32 count; - - /// - float32* masses; - - /// - b2Vec2 gravity; - - /// - float32 damping; - - /// Stretching stiffness - float32 k2; - - /// Bending stiffness. Values above 0.5 can make the simulation blow up. - float32 k3; -}; - -/// -class b2Rope -{ -public: - b2Rope(); - ~b2Rope(); - - /// - void Initialize(const b2RopeDef* def); - - /// - void Step(float32 timeStep, int32 iterations); - - /// - int32 GetVertexCount() const - { - return m_count; - } - - /// - const b2Vec2* GetVertices() const - { - return m_ps; - } - - /// - void Draw(b2Draw* draw) const; - - /// - void SetAngle(float32 angle); - -private: - - void SolveC2(); - void SolveC3(); - - int32 m_count; - b2Vec2* m_ps; - b2Vec2* m_p0s; - b2Vec2* m_vs; - - float32* m_ims; - - float32* m_Ls; - float32* m_as; - - b2Vec2 m_gravity; - float32 m_damping; - - float32 m_k2; - float32 m_k3; -}; - -#endif diff --git a/external/Box2D/proj.linux/.cproject b/external/Box2D/proj.linux/.cproject deleted file mode 100644 index 5aa092cac3..0000000000 --- a/external/Box2D/proj.linux/.cproject +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/Box2D/proj.linux/.project b/external/Box2D/proj.linux/.project deleted file mode 100644 index 164d50f52a..0000000000 --- a/external/Box2D/proj.linux/.project +++ /dev/null @@ -1,110 +0,0 @@ - - - libBox2D - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/libBox2D/Debug} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - - - Box2D.h - 1 - PARENT-1-PROJECT_LOC/Box2D.h - - - Collision - 2 - PARENT-1-PROJECT_LOC/Collision - - - Common - 2 - PARENT-1-PROJECT_LOC/Common - - - Dynamics - 2 - PARENT-1-PROJECT_LOC/Dynamics - - - Rope - 2 - PARENT-1-PROJECT_LOC/Rope - - - diff --git a/external/Box2D/proj.linux/Makefile b/external/Box2D/proj.linux/Makefile deleted file mode 100644 index e430bc9883..0000000000 --- a/external/Box2D/proj.linux/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -TARGET = libbox2d.a - -SOURCES = ../Collision/Shapes/b2ChainShape.cpp \ -../Collision/Shapes/b2CircleShape.cpp \ -../Collision/Shapes/b2EdgeShape.cpp \ -../Collision/Shapes/b2PolygonShape.cpp \ -../Collision/b2BroadPhase.cpp \ -../Collision/b2CollideCircle.cpp \ -../Collision/b2CollideEdge.cpp \ -../Collision/b2CollidePolygon.cpp \ -../Collision/b2Collision.cpp \ -../Collision/b2Distance.cpp \ -../Collision/b2DynamicTree.cpp \ -../Collision/b2TimeOfImpact.cpp \ -../Common/b2BlockAllocator.cpp \ -../Common/b2Draw.cpp \ -../Common/b2Math.cpp \ -../Common/b2Settings.cpp \ -../Common/b2StackAllocator.cpp \ -../Common/b2Timer.cpp \ -../Dynamics/Contacts/b2ChainAndCircleContact.cpp \ -../Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ -../Dynamics/Contacts/b2CircleContact.cpp \ -../Dynamics/Contacts/b2Contact.cpp \ -../Dynamics/Contacts/b2ContactSolver.cpp \ -../Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ -../Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ -../Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ -../Dynamics/Contacts/b2PolygonContact.cpp \ -../Dynamics/Joints/b2DistanceJoint.cpp \ -../Dynamics/Joints/b2FrictionJoint.cpp \ -../Dynamics/Joints/b2GearJoint.cpp \ -../Dynamics/Joints/b2Joint.cpp \ -../Dynamics/Joints/b2MouseJoint.cpp \ -../Dynamics/Joints/b2PrismaticJoint.cpp \ -../Dynamics/Joints/b2PulleyJoint.cpp \ -../Dynamics/Joints/b2RevoluteJoint.cpp \ -../Dynamics/Joints/b2RopeJoint.cpp \ -../Dynamics/Joints/b2WeldJoint.cpp \ -../Dynamics/Joints/b2WheelJoint.cpp \ -../Dynamics/b2Body.cpp \ -../Dynamics/b2ContactManager.cpp \ -../Dynamics/b2Fixture.cpp \ -../Dynamics/b2Island.cpp \ -../Dynamics/b2World.cpp \ -../Dynamics/b2WorldCallbacks.cpp \ -../Rope/b2Rope.cpp - -include ../../../cocos2dx/proj.linux/cocos2dx.mk - -INCLUDES = -I../.. - -# Cocos2d is not responsible for warnings in external projects -CXXFLAGS += -w - -ifeq ($(DEBUG), 1) -DEFINES = -D_DEBUG -else -DEFINES = -endif - -TARGET := $(LIB_DIR)/$(TARGET) - -all: $(TARGET) - -$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_AR)$(AR) $(ARFLAGS) $(TARGET) $(OBJECTS) - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/external/Box2D/proj.linux/box2d.prf b/external/Box2D/proj.linux/box2d.prf deleted file mode 100644 index 434ad88406..0000000000 --- a/external/Box2D/proj.linux/box2d.prf +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Do not include this file in your project: see cocos2dx.pri. -################################################################################ - -linux { - # We will compile box2d on demand using Makefile. - build_box2d.name = Build box2d static library - build_box2d.input = $$PWD/Makefile - build_box2d.output = $$CC_LIBRARY_DIR/libbox2d.a - build_box2d.target = $$CC_LIBRARY_DIR/libbox2d.a - build_box2d.CONFIG = no_link target_predeps - build_box2d.commands = cd $$PWD && make $$CC_MAKE_FLAGS - - QMAKE_EXTRA_COMPILERS += build_box2d - QMAKE_EXTRA_TARGETS += build_box2d - - PRE_TARGETDEPS += $$CC_LIBRARY_DIR/libbox2d.a - LIBS += -Wl,-Bstatic -lbox2d -Wl,-Bdynamic -} diff --git a/external/Box2D/proj.win32/Box2D.vcxproj b/external/Box2D/proj.win32/Box2D.vcxproj deleted file mode 100644 index cd4bd2086c..0000000000 --- a/external/Box2D/proj.win32/Box2D.vcxproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - libBox2D - {929480E7-23C0-4DF6-8456-096D71547116} - Box2D.win32 - Win32Proj - - - - StaticLibrary - Unicode - v100 - v110 - v110_xp - - - StaticLibrary - Unicode - v100 - v110 - v110_xp - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration).win32\ - $(Configuration).win32\ - $(SolutionDir)$(Configuration).win32\ - $(Configuration).win32\ - AllRules.ruleset - - - AllRules.ruleset - - - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) - - - - Disabled - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - true - - - $(OutDir)$(ProjectName).lib - - - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - - - $(OutDir)$(ProjectName).lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/external/Box2D/proj.win32/Box2D.vcxproj.filters b/external/Box2D/proj.win32/Box2D.vcxproj.filters deleted file mode 100644 index e810cbb0cf..0000000000 --- a/external/Box2D/proj.win32/Box2D.vcxproj.filters +++ /dev/null @@ -1,301 +0,0 @@ - - - - - {bdf099c5-cc32-468b-b53f-ec010d7f823f} - - - {92792f88-4e5c-46ee-8d87-002f3b2297ae} - - - {f41a6fa6-5ac1-4514-9ac0-6f3a38f35b4d} - - - {0b56913a-34b7-410a-b386-869d6f7a20be} - - - {f0e7b230-79cc-49b8-9ed7-9dbfa062f2a4} - - - {932f2008-afbe-42f5-993d-a1df0ec67756} - - - {f8937e09-93a4-49fa-8f3e-dfc36da764df} - - - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Rope - - - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Rope - - - - \ No newline at end of file diff --git a/external/Box2D/proj.win32/Box2D.vcxproj.user b/external/Box2D/proj.win32/Box2D.vcxproj.user deleted file mode 100644 index ace9a86acb..0000000000 --- a/external/Box2D/proj.win32/Box2D.vcxproj.user +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file From 19ee87e29a16bc086e2b2eb3e5582d87b27fd970 Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 14:03:04 +0800 Subject: [PATCH 109/116] issue #2905: step2 Box2D -> box2d --- cocos/physics/box2d/CCPhysicsBodyInfo.cpp | 39 + cocos/physics/box2d/CCPhysicsBodyInfo.h | 43 + cocos/physics/box2d/CCPhysicsContactInfo.cpp | 39 + cocos/physics/box2d/CCPhysicsContactInfo.h | 43 + cocos/physics/box2d/CCPhysicsHelper.h | 43 + cocos/physics/box2d/CCPhysicsJointInfo.cpp | 39 + cocos/physics/box2d/CCPhysicsJointInfo.h | 43 + cocos/physics/box2d/CCPhysicsShapeInfo.cpp | 39 + cocos/physics/box2d/CCPhysicsShapeInfo.h | 43 + cocos/physics/box2d/CCPhysicsWorldInfo.cpp | 39 + cocos/physics/box2d/CCPhysicsWorldInfo.h | 43 + external/box2d/Android.mk | 60 + external/box2d/Box2D.h | 67 + .../box2d/Collision/Shapes/b2ChainShape.cpp | 171 +++ .../box2d/Collision/Shapes/b2ChainShape.h | 102 ++ .../box2d/Collision/Shapes/b2CircleShape.cpp | 100 ++ .../box2d/Collision/Shapes/b2CircleShape.h | 91 ++ .../box2d/Collision/Shapes/b2EdgeShape.cpp | 139 ++ external/box2d/Collision/Shapes/b2EdgeShape.h | 74 + .../box2d/Collision/Shapes/b2PolygonShape.cpp | 361 +++++ .../box2d/Collision/Shapes/b2PolygonShape.h | 95 ++ external/box2d/Collision/Shapes/b2Shape.h | 101 ++ external/box2d/Collision/b2BroadPhase.cpp | 122 ++ external/box2d/Collision/b2BroadPhase.h | 248 ++++ external/box2d/Collision/b2CollideCircle.cpp | 154 ++ external/box2d/Collision/b2CollideEdge.cpp | 698 +++++++++ external/box2d/Collision/b2CollidePolygon.cpp | 317 ++++ external/box2d/Collision/b2Collision.cpp | 249 ++++ external/box2d/Collision/b2Collision.h | 276 ++++ external/box2d/Collision/b2Distance.cpp | 603 ++++++++ external/box2d/Collision/b2Distance.h | 141 ++ external/box2d/Collision/b2DynamicTree.cpp | 775 ++++++++++ external/box2d/Collision/b2DynamicTree.h | 284 ++++ external/box2d/Collision/b2TimeOfImpact.cpp | 488 ++++++ external/box2d/Collision/b2TimeOfImpact.h | 58 + external/box2d/Common/b2BlockAllocator.cpp | 218 +++ external/box2d/Common/b2BlockAllocator.h | 62 + external/box2d/Common/b2Draw.cpp | 44 + external/box2d/Common/b2Draw.h | 81 + external/box2d/Common/b2GrowableStack.h | 85 ++ external/box2d/Common/b2Math.cpp | 94 ++ external/box2d/Common/b2Math.h | 738 +++++++++ external/box2d/Common/b2Settings.cpp | 61 + external/box2d/Common/b2Settings.h | 150 ++ external/box2d/Common/b2StackAllocator.cpp | 83 ++ external/box2d/Common/b2StackAllocator.h | 60 + external/box2d/Common/b2Timer.cpp | 100 ++ external/box2d/Common/b2Timer.h | 45 + .../Contacts/b2ChainAndCircleContact.cpp | 54 + .../Contacts/b2ChainAndCircleContact.h | 39 + .../Contacts/b2ChainAndPolygonContact.cpp | 54 + .../Contacts/b2ChainAndPolygonContact.h | 39 + .../Dynamics/Contacts/b2CircleContact.cpp | 53 + .../box2d/Dynamics/Contacts/b2CircleContact.h | 39 + .../box2d/Dynamics/Contacts/b2Contact.cpp | 240 +++ external/box2d/Dynamics/Contacts/b2Contact.h | 331 +++++ .../Dynamics/Contacts/b2ContactSolver.cpp | 832 +++++++++++ .../box2d/Dynamics/Contacts/b2ContactSolver.h | 94 ++ .../Contacts/b2EdgeAndCircleContact.cpp | 50 + .../Contacts/b2EdgeAndCircleContact.h | 39 + .../Contacts/b2EdgeAndPolygonContact.cpp | 50 + .../Contacts/b2EdgeAndPolygonContact.h | 39 + .../Contacts/b2PolygonAndCircleContact.cpp | 50 + .../Contacts/b2PolygonAndCircleContact.h | 38 + .../Dynamics/Contacts/b2PolygonContact.cpp | 53 + .../Dynamics/Contacts/b2PolygonContact.h | 39 + .../box2d/Dynamics/Joints/b2DistanceJoint.cpp | 260 ++++ .../box2d/Dynamics/Joints/b2DistanceJoint.h | 169 +++ .../box2d/Dynamics/Joints/b2FrictionJoint.cpp | 251 ++++ .../box2d/Dynamics/Joints/b2FrictionJoint.h | 119 ++ .../box2d/Dynamics/Joints/b2GearJoint.cpp | 423 ++++++ external/box2d/Dynamics/Joints/b2GearJoint.h | 125 ++ external/box2d/Dynamics/Joints/b2Joint.cpp | 199 +++ external/box2d/Dynamics/Joints/b2Joint.h | 222 +++ .../box2d/Dynamics/Joints/b2MouseJoint.cpp | 217 +++ external/box2d/Dynamics/Joints/b2MouseJoint.h | 126 ++ .../Dynamics/Joints/b2PrismaticJoint.cpp | 637 ++++++++ .../box2d/Dynamics/Joints/b2PrismaticJoint.h | 196 +++ .../box2d/Dynamics/Joints/b2PulleyJoint.cpp | 332 +++++ .../box2d/Dynamics/Joints/b2PulleyJoint.h | 143 ++ .../box2d/Dynamics/Joints/b2RevoluteJoint.cpp | 504 +++++++ .../box2d/Dynamics/Joints/b2RevoluteJoint.h | 204 +++ .../box2d/Dynamics/Joints/b2RopeJoint.cpp | 241 +++ external/box2d/Dynamics/Joints/b2RopeJoint.h | 114 ++ .../box2d/Dynamics/Joints/b2WeldJoint.cpp | 330 +++++ external/box2d/Dynamics/Joints/b2WeldJoint.h | 126 ++ .../box2d/Dynamics/Joints/b2WheelJoint.cpp | 419 ++++++ external/box2d/Dynamics/Joints/b2WheelJoint.h | 213 +++ external/box2d/Dynamics/b2Body.cpp | 514 +++++++ external/box2d/Dynamics/b2Body.h | 846 +++++++++++ external/box2d/Dynamics/b2ContactManager.cpp | 293 ++++ external/box2d/Dynamics/b2ContactManager.h | 52 + external/box2d/Dynamics/b2Fixture.cpp | 303 ++++ external/box2d/Dynamics/b2Fixture.h | 345 +++++ external/box2d/Dynamics/b2Island.cpp | 539 +++++++ external/box2d/Dynamics/b2Island.h | 93 ++ external/box2d/Dynamics/b2TimeStep.h | 70 + external/box2d/Dynamics/b2World.cpp | 1316 +++++++++++++++++ external/box2d/Dynamics/b2World.h | 349 +++++ external/box2d/Dynamics/b2WorldCallbacks.cpp | 36 + external/box2d/Dynamics/b2WorldCallbacks.h | 155 ++ external/box2d/Rope/b2Rope.cpp | 259 ++++ external/box2d/Rope/b2Rope.h | 115 ++ external/box2d/proj.linux/.cproject | 267 ++++ external/box2d/proj.linux/.project | 110 ++ external/box2d/proj.linux/Makefile | 72 + external/box2d/proj.linux/box2d.prf | 19 + external/box2d/proj.win32/Box2D.vcxproj | 194 +++ .../box2d/proj.win32/Box2D.vcxproj.filters | 301 ++++ external/box2d/proj.win32/Box2D.vcxproj.user | 3 + 110 files changed, 22002 insertions(+) create mode 100644 cocos/physics/box2d/CCPhysicsBodyInfo.cpp create mode 100644 cocos/physics/box2d/CCPhysicsBodyInfo.h create mode 100644 cocos/physics/box2d/CCPhysicsContactInfo.cpp create mode 100644 cocos/physics/box2d/CCPhysicsContactInfo.h create mode 100644 cocos/physics/box2d/CCPhysicsHelper.h create mode 100644 cocos/physics/box2d/CCPhysicsJointInfo.cpp create mode 100644 cocos/physics/box2d/CCPhysicsJointInfo.h create mode 100644 cocos/physics/box2d/CCPhysicsShapeInfo.cpp create mode 100644 cocos/physics/box2d/CCPhysicsShapeInfo.h create mode 100644 cocos/physics/box2d/CCPhysicsWorldInfo.cpp create mode 100644 cocos/physics/box2d/CCPhysicsWorldInfo.h create mode 100644 external/box2d/Android.mk create mode 100644 external/box2d/Box2D.h create mode 100644 external/box2d/Collision/Shapes/b2ChainShape.cpp create mode 100644 external/box2d/Collision/Shapes/b2ChainShape.h create mode 100644 external/box2d/Collision/Shapes/b2CircleShape.cpp create mode 100644 external/box2d/Collision/Shapes/b2CircleShape.h create mode 100644 external/box2d/Collision/Shapes/b2EdgeShape.cpp create mode 100644 external/box2d/Collision/Shapes/b2EdgeShape.h create mode 100644 external/box2d/Collision/Shapes/b2PolygonShape.cpp create mode 100644 external/box2d/Collision/Shapes/b2PolygonShape.h create mode 100644 external/box2d/Collision/Shapes/b2Shape.h create mode 100644 external/box2d/Collision/b2BroadPhase.cpp create mode 100644 external/box2d/Collision/b2BroadPhase.h create mode 100644 external/box2d/Collision/b2CollideCircle.cpp create mode 100644 external/box2d/Collision/b2CollideEdge.cpp create mode 100644 external/box2d/Collision/b2CollidePolygon.cpp create mode 100644 external/box2d/Collision/b2Collision.cpp create mode 100644 external/box2d/Collision/b2Collision.h create mode 100644 external/box2d/Collision/b2Distance.cpp create mode 100644 external/box2d/Collision/b2Distance.h create mode 100644 external/box2d/Collision/b2DynamicTree.cpp create mode 100644 external/box2d/Collision/b2DynamicTree.h create mode 100644 external/box2d/Collision/b2TimeOfImpact.cpp create mode 100644 external/box2d/Collision/b2TimeOfImpact.h create mode 100644 external/box2d/Common/b2BlockAllocator.cpp create mode 100644 external/box2d/Common/b2BlockAllocator.h create mode 100644 external/box2d/Common/b2Draw.cpp create mode 100644 external/box2d/Common/b2Draw.h create mode 100644 external/box2d/Common/b2GrowableStack.h create mode 100644 external/box2d/Common/b2Math.cpp create mode 100644 external/box2d/Common/b2Math.h create mode 100644 external/box2d/Common/b2Settings.cpp create mode 100644 external/box2d/Common/b2Settings.h create mode 100644 external/box2d/Common/b2StackAllocator.cpp create mode 100644 external/box2d/Common/b2StackAllocator.h create mode 100644 external/box2d/Common/b2Timer.cpp create mode 100644 external/box2d/Common/b2Timer.h create mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2CircleContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2CircleContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2Contact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2Contact.h create mode 100644 external/box2d/Dynamics/Contacts/b2ContactSolver.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2ContactSolver.h create mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h create mode 100644 external/box2d/Dynamics/Contacts/b2PolygonContact.cpp create mode 100644 external/box2d/Dynamics/Contacts/b2PolygonContact.h create mode 100644 external/box2d/Dynamics/Joints/b2DistanceJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2DistanceJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2FrictionJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2FrictionJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2GearJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2GearJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2Joint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2Joint.h create mode 100644 external/box2d/Dynamics/Joints/b2MouseJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2MouseJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2PrismaticJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2PulleyJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2PulleyJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2RevoluteJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2RopeJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2RopeJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2WeldJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2WeldJoint.h create mode 100644 external/box2d/Dynamics/Joints/b2WheelJoint.cpp create mode 100644 external/box2d/Dynamics/Joints/b2WheelJoint.h create mode 100644 external/box2d/Dynamics/b2Body.cpp create mode 100644 external/box2d/Dynamics/b2Body.h create mode 100644 external/box2d/Dynamics/b2ContactManager.cpp create mode 100644 external/box2d/Dynamics/b2ContactManager.h create mode 100644 external/box2d/Dynamics/b2Fixture.cpp create mode 100644 external/box2d/Dynamics/b2Fixture.h create mode 100644 external/box2d/Dynamics/b2Island.cpp create mode 100644 external/box2d/Dynamics/b2Island.h create mode 100644 external/box2d/Dynamics/b2TimeStep.h create mode 100644 external/box2d/Dynamics/b2World.cpp create mode 100644 external/box2d/Dynamics/b2World.h create mode 100644 external/box2d/Dynamics/b2WorldCallbacks.cpp create mode 100644 external/box2d/Dynamics/b2WorldCallbacks.h create mode 100644 external/box2d/Rope/b2Rope.cpp create mode 100644 external/box2d/Rope/b2Rope.h create mode 100644 external/box2d/proj.linux/.cproject create mode 100644 external/box2d/proj.linux/.project create mode 100644 external/box2d/proj.linux/Makefile create mode 100644 external/box2d/proj.linux/box2d.prf create mode 100644 external/box2d/proj.win32/Box2D.vcxproj create mode 100644 external/box2d/proj.win32/Box2D.vcxproj.filters create mode 100644 external/box2d/proj.win32/Box2D.vcxproj.user diff --git a/cocos/physics/box2d/CCPhysicsBodyInfo.cpp b/cocos/physics/box2d/CCPhysicsBodyInfo.cpp new file mode 100644 index 0000000000..bfa20b616a --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsBodyInfo.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCPhysicsBodyInfo.h" + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) +NS_CC_BEGIN + +PhysicsBodyInfo::PhysicsBodyInfo() +{ +} + +PhysicsBodyInfo::~PhysicsBodyInfo() +{ +} + +NS_CC_END +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsBodyInfo.h b/cocos/physics/box2d/CCPhysicsBodyInfo.h new file mode 100644 index 0000000000..730837ed9d --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsBodyInfo.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_BODY_INFO_H__ +#define __CCPHYSICS_BODY_INFO_H__ +#include "platform/CCPlatformMacros.h" +NS_CC_BEGIN + +class PhysicsBodyInfo +{ +public: + PhysicsBodyInfo(); + ~PhysicsBodyInfo(); +}; + +NS_CC_END +#endif // __CCPHYSICS_BODY_INFO_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsContactInfo.cpp b/cocos/physics/box2d/CCPhysicsContactInfo.cpp new file mode 100644 index 0000000000..41eaa4f831 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsContactInfo.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCPhysicsContactInfo.h" + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) +NS_CC_BEGIN + +PhysicsContactInfo::PhysicsContactInfo() +{ +} + +PhysicsContactInfo::~PhysicsContactInfo() +{ +} + +NS_CC_END +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsContactInfo.h b/cocos/physics/box2d/CCPhysicsContactInfo.h new file mode 100644 index 0000000000..b592caa0af --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsContactInfo.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_CONTACT_INFO_H__ +#define __CCPHYSICS_CONTACT_INFO_H__ +#include "platform/CCPlatformMacros.h" +NS_CC_BEGIN + +class PhysicsContactInfo +{ +public: + PhysicsContactInfo(); + ~PhysicsContactInfo(); +}; + +NS_CC_END +#endif // __CCPHYSICS_CONTACT_INFO_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsHelper.h b/cocos/physics/box2d/CCPhysicsHelper.h new file mode 100644 index 0000000000..86ef7d74ee --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsHelper.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_HELPER_H__ +#define __CCPHYSICS_HELPER_H__ + +#include "platform/CCPlatformMacros.h" +#include "cocoa/CCGeometry.h" + +NS_CC_BEGIN + +class PhysicsHelper +{ +}; + +NS_CC_END +#endif // __CCPHYSICS_HELPER_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsJointInfo.cpp b/cocos/physics/box2d/CCPhysicsJointInfo.cpp new file mode 100644 index 0000000000..753ba41534 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsJointInfo.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCPhysicsJointInfo.h" + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) +NS_CC_BEGIN + +PhysicsJointInfo::PhysicsJointInfo() +{ +} + +PhysicsJointInfo::~PhysicsJointInfo() +{ +} + +NS_CC_END +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsJointInfo.h b/cocos/physics/box2d/CCPhysicsJointInfo.h new file mode 100644 index 0000000000..abcf089387 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsJointInfo.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_JOINT_INFO_H__ +#define __CCPHYSICS_JOINT_INFO_H__ +#include "platform/CCPlatformMacros.h" +NS_CC_BEGIN + +class PhysicsJointInfo +{ +public: + PhysicsJointInfo(); + ~PhysicsJointInfo(); +}; + +NS_CC_END +#endif // __CCPHYSICS_JOINT_INFO_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsShapeInfo.cpp b/cocos/physics/box2d/CCPhysicsShapeInfo.cpp new file mode 100644 index 0000000000..a89ba7dae7 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsShapeInfo.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCPhysicsShapeInfo.h" + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) +NS_CC_BEGIN + +PhysicsShapeInfo::PhysicsShapeInfo() +{ +} + +PhysicsShapeInfo::~PhysicsShapeInfo() +{ +} + +NS_CC_END +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsShapeInfo.h b/cocos/physics/box2d/CCPhysicsShapeInfo.h new file mode 100644 index 0000000000..9091001887 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsShapeInfo.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_SHAPE_INFO_H__ +#define __CCPHYSICS_SHAPE_INFO_H__ +#include "platform/CCPlatformMacros.h" +NS_CC_BEGIN + +class PhysicsShapeInfo +{ +public: + PhysicsShapeInfo(); + ~PhysicsShapeInfo(); +}; + +NS_CC_END +#endif // __CCPHYSICS_SHAPE_INFO_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsWorldInfo.cpp b/cocos/physics/box2d/CCPhysicsWorldInfo.cpp new file mode 100644 index 0000000000..0de6c00d82 --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsWorldInfo.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCPhysicsWorldInfo.h" + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) +NS_CC_BEGIN + +PhysicsWorldInfo::PhysicsWorldInfo() +{ +} + +PhysicsWorldInfo::~PhysicsWorldInfo() +{ +} + +NS_CC_END +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/cocos/physics/box2d/CCPhysicsWorldInfo.h b/cocos/physics/box2d/CCPhysicsWorldInfo.h new file mode 100644 index 0000000000..bcc09124db --- /dev/null +++ b/cocos/physics/box2d/CCPhysicsWorldInfo.h @@ -0,0 +1,43 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "../CCPhysicsSetting.h" +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) + +#ifndef __CCPHYSICS_WORLD_INFO_H__ +#define __CCPHYSICS_WORLD_INFO_H__ +#include "platform/CCPlatformMacros.h" +NS_CC_BEGIN + +class PhysicsWorldInfo +{ +public: + PhysicsWorldInfo(); + ~PhysicsWorldInfo(); +}; + +NS_CC_END +#endif // __CCPHYSICS_WORLD_INFO_H__ + +#endif // CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D diff --git a/external/box2d/Android.mk b/external/box2d/Android.mk new file mode 100644 index 0000000000..c366750c01 --- /dev/null +++ b/external/box2d/Android.mk @@ -0,0 +1,60 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := box2d_static + +LOCAL_MODULE_FILENAME := libbox2d + +LOCAL_SRC_FILES := \ +Collision/b2BroadPhase.cpp \ +Collision/b2CollideCircle.cpp \ +Collision/b2CollideEdge.cpp \ +Collision/b2CollidePolygon.cpp \ +Collision/b2Collision.cpp \ +Collision/b2Distance.cpp \ +Collision/b2DynamicTree.cpp \ +Collision/b2TimeOfImpact.cpp \ +Collision/Shapes/b2ChainShape.cpp \ +Collision/Shapes/b2CircleShape.cpp \ +Collision/Shapes/b2EdgeShape.cpp \ +Collision/Shapes/b2PolygonShape.cpp \ +Common/b2BlockAllocator.cpp \ +Common/b2Draw.cpp \ +Common/b2Math.cpp \ +Common/b2Settings.cpp \ +Common/b2StackAllocator.cpp \ +Common/b2Timer.cpp \ +Dynamics/b2Body.cpp \ +Dynamics/b2ContactManager.cpp \ +Dynamics/b2Fixture.cpp \ +Dynamics/b2Island.cpp \ +Dynamics/b2World.cpp \ +Dynamics/b2WorldCallbacks.cpp \ +Dynamics/Contacts/b2ChainAndCircleContact.cpp \ +Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ +Dynamics/Contacts/b2CircleContact.cpp \ +Dynamics/Contacts/b2Contact.cpp \ +Dynamics/Contacts/b2ContactSolver.cpp \ +Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ +Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ +Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ +Dynamics/Contacts/b2PolygonContact.cpp \ +Dynamics/Joints/b2DistanceJoint.cpp \ +Dynamics/Joints/b2FrictionJoint.cpp \ +Dynamics/Joints/b2GearJoint.cpp \ +Dynamics/Joints/b2Joint.cpp \ +Dynamics/Joints/b2MouseJoint.cpp \ +Dynamics/Joints/b2PrismaticJoint.cpp \ +Dynamics/Joints/b2PulleyJoint.cpp \ +Dynamics/Joints/b2RevoluteJoint.cpp \ +Dynamics/Joints/b2RopeJoint.cpp \ +Dynamics/Joints/b2WeldJoint.cpp \ +Dynamics/Joints/b2WheelJoint.cpp \ +Rope/b2Rope.cpp + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. + +include $(BUILD_STATIC_LIBRARY) diff --git a/external/box2d/Box2D.h b/external/box2d/Box2D.h new file mode 100644 index 0000000000..f674d82269 --- /dev/null +++ b/external/box2d/Box2D.h @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef BOX2D_H +#define BOX2D_H + +/** +\mainpage Box2D API Documentation + +\section intro_sec Getting Started + +For documentation please see http://box2d.org/documentation.html + +For discussion please visit http://box2d.org/forum +*/ + +// These include files constitute the main Box2D API + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/external/box2d/Collision/Shapes/b2ChainShape.cpp b/external/box2d/Collision/Shapes/b2ChainShape.cpp new file mode 100644 index 0000000000..79b4304b5b --- /dev/null +++ b/external/box2d/Collision/Shapes/b2ChainShape.cpp @@ -0,0 +1,171 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +using namespace std; + +b2ChainShape::~b2ChainShape() +{ + b2Free(m_vertices); + m_vertices = NULL; + m_count = 0; +} + +void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 3); + m_count = count + 1; + m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); + m_vertices[count] = m_vertices[0]; + m_prevVertex = m_vertices[m_count - 2]; + m_nextVertex = m_vertices[1]; + m_hasPrevVertex = true; + m_hasNextVertex = true; +} + +void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 2); + m_count = count; + m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) +{ + m_prevVertex = prevVertex; + m_hasPrevVertex = true; +} + +void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) +{ + m_nextVertex = nextVertex; + m_hasNextVertex = true; +} + +b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2ChainShape)); + b2ChainShape* clone = new (mem) b2ChainShape; + clone->CreateChain(m_vertices, m_count); + clone->m_prevVertex = m_prevVertex; + clone->m_nextVertex = m_nextVertex; + clone->m_hasPrevVertex = m_hasPrevVertex; + clone->m_hasNextVertex = m_hasNextVertex; + return clone; +} + +int32 b2ChainShape::GetChildCount() const +{ + // edge count = vertex count - 1 + return m_count - 1; +} + +void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const +{ + b2Assert(0 <= index && index < m_count - 1); + edge->m_type = b2Shape::e_edge; + edge->m_radius = m_radius; + + edge->m_vertex1 = m_vertices[index + 0]; + edge->m_vertex2 = m_vertices[index + 1]; + + if (index > 0) + { + edge->m_vertex0 = m_vertices[index - 1]; + edge->m_hasVertex0 = true; + } + else + { + edge->m_vertex0 = m_prevVertex; + edge->m_hasVertex0 = m_hasPrevVertex; + } + + if (index < m_count - 2) + { + edge->m_vertex3 = m_vertices[index + 2]; + edge->m_hasVertex3 = true; + } + else + { + edge->m_vertex3 = m_nextVertex; + edge->m_hasVertex3 = m_hasNextVertex; + } +} + +bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + b2EdgeShape edgeShape; + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + edgeShape.m_vertex1 = m_vertices[i1]; + edgeShape.m_vertex2 = m_vertices[i2]; + + return edgeShape.RayCast(output, input, xf, 0); +} + +void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); + b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); + + aabb->lowerBound = b2Min(v1, v2); + aabb->upperBound = b2Max(v1, v2); +} + +void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center.SetZero(); + massData->I = 0.0f; +} diff --git a/external/box2d/Collision/Shapes/b2ChainShape.h b/external/box2d/Collision/Shapes/b2ChainShape.h new file mode 100644 index 0000000000..9c9a9eaa7d --- /dev/null +++ b/external/box2d/Collision/Shapes/b2ChainShape.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2006-2010 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. +*/ + +#ifndef B2_CHAIN_SHAPE_H +#define B2_CHAIN_SHAPE_H + +#include + +class b2EdgeShape; + +/// A chain shape is a free form sequence of line segments. +/// The chain has two-sided collision, so you can use inside and outside collision. +/// Therefore, you may use any winding order. +/// Since there may be many vertices, they are allocated using b2Alloc. +/// Connectivity information is used to create smooth collisions. +/// WARNING: The chain will not collide properly if there are self-intersections. +class b2ChainShape : public b2Shape +{ +public: + b2ChainShape(); + + /// The destructor frees the vertices using b2Free. + ~b2ChainShape(); + + /// Create a loop. This automatically adjusts connectivity. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateLoop(const b2Vec2* vertices, int32 count); + + /// Create a chain with isolated end vertices. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateChain(const b2Vec2* vertices, int32 count); + + /// Establish connectivity to a vertex that precedes the first vertex. + /// Don't call this for loops. + void SetPrevVertex(const b2Vec2& prevVertex); + + /// Establish connectivity to a vertex that follows the last vertex. + /// Don't call this for loops. + void SetNextVertex(const b2Vec2& nextVertex); + + /// Implement b2Shape. Vertices are cloned using b2Alloc. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Get a child edge. + void GetChildEdge(b2EdgeShape* edge, int32 index) const; + + /// This always return false. + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// Chains have zero mass. + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// The vertices. Owned by this class. + b2Vec2* m_vertices; + + /// The vertex count. + int32 m_count; + + b2Vec2 m_prevVertex, m_nextVertex; + bool m_hasPrevVertex, m_hasNextVertex; +}; + +inline b2ChainShape::b2ChainShape() +{ + m_type = e_chain; + m_radius = b2_polygonRadius; + m_vertices = NULL; + m_count = 0; + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +#endif diff --git a/external/box2d/Collision/Shapes/b2CircleShape.cpp b/external/box2d/Collision/Shapes/b2CircleShape.cpp new file mode 100644 index 0000000000..587ca960b2 --- /dev/null +++ b/external/box2d/Collision/Shapes/b2CircleShape.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2006-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 +#include +using namespace std; + +b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2CircleShape)); + b2CircleShape* clone = new (mem) b2CircleShape; + *clone = *this; + return clone; +} + +int32 b2CircleShape::GetChildCount() const +{ + return 1; +} + +bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const +{ + b2Vec2 center = transform.p + b2Mul(transform.q, m_p); + b2Vec2 d = p - center; + return b2Dot(d, d) <= m_radius * m_radius; +} + +// Collision Detection in Interactive 3D Environments by Gino van den Bergen +// From Section 3.1.2 +// x = s + a * r +// norm(x) = radius +bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 position = transform.p + b2Mul(transform.q, m_p); + b2Vec2 s = input.p1 - position; + float32 b = b2Dot(s, s) - m_radius * m_radius; + + // Solve quadratic equation. + b2Vec2 r = input.p2 - input.p1; + float32 c = b2Dot(s, r); + float32 rr = b2Dot(r, r); + float32 sigma = c * c - rr * b; + + // Check for negative discriminant and short segment. + if (sigma < 0.0f || rr < b2_epsilon) + { + return false; + } + + // Find the point of intersection of the line with the circle. + float32 a = -(c + b2Sqrt(sigma)); + + // Is the intersection point on the segment? + if (0.0f <= a && a <= input.maxFraction * rr) + { + a /= rr; + output->fraction = a; + output->normal = s + a * r; + output->normal.Normalize(); + return true; + } + + return false; +} + +void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 p = transform.p + b2Mul(transform.q, m_p); + aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); + aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); +} + +void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const +{ + massData->mass = density * b2_pi * m_radius * m_radius; + massData->center = m_p; + + // inertia about the local origin + massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); +} diff --git a/external/box2d/Collision/Shapes/b2CircleShape.h b/external/box2d/Collision/Shapes/b2CircleShape.h new file mode 100644 index 0000000000..c4e23a475b --- /dev/null +++ b/external/box2d/Collision/Shapes/b2CircleShape.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CIRCLE_SHAPE_H +#define B2_CIRCLE_SHAPE_H + +#include + +/// A circle shape. +class b2CircleShape : public b2Shape +{ +public: + b2CircleShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Implement b2Shape. + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return 1; } + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + /// Position + b2Vec2 m_p; +}; + +inline b2CircleShape::b2CircleShape() +{ + m_type = e_circle; + m_radius = 0.0f; + m_p.SetZero(); +} + +inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return 0; +} + +inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return m_p; +} + +inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const +{ + B2_NOT_USED(index); + b2Assert(index == 0); + return m_p; +} + +#endif diff --git a/external/box2d/Collision/Shapes/b2EdgeShape.cpp b/external/box2d/Collision/Shapes/b2EdgeShape.cpp new file mode 100644 index 0000000000..7b09e55bf4 --- /dev/null +++ b/external/box2d/Collision/Shapes/b2EdgeShape.cpp @@ -0,0 +1,139 @@ +/* +* Copyright (c) 2006-2010 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 +#include +using namespace std; + +void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) +{ + m_vertex1 = v1; + m_vertex2 = v2; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2EdgeShape)); + b2EdgeShape* clone = new (mem) b2EdgeShape; + *clone = *this; + return clone; +} + +int32 b2EdgeShape::GetChildCount() const +{ + return 1; +} + +bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +// p = p1 + t * d +// v = v1 + s * e +// p1 + t * d = v1 + s * e +// s * e - t * d = p1 - v1 +bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the edge's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + b2Vec2 v1 = m_vertex1; + b2Vec2 v2 = m_vertex2; + b2Vec2 e = v2 - v1; + b2Vec2 normal(e.y, -e.x); + normal.Normalize(); + + // q = p1 + t * d + // dot(normal, q - v1) = 0 + // dot(normal, p1 - v1) + t * dot(normal, d) = 0 + float32 numerator = b2Dot(normal, v1 - p1); + float32 denominator = b2Dot(normal, d); + + if (denominator == 0.0f) + { + return false; + } + + float32 t = numerator / denominator; + if (t < 0.0f || input.maxFraction < t) + { + return false; + } + + b2Vec2 q = p1 + t * d; + + // q = v1 + s * r + // s = dot(q - v1, r) / dot(r, r) + b2Vec2 r = v2 - v1; + float32 rr = b2Dot(r, r); + if (rr == 0.0f) + { + return false; + } + + float32 s = b2Dot(q - v1, r) / rr; + if (s < 0.0f || 1.0f < s) + { + return false; + } + + output->fraction = t; + if (numerator > 0.0f) + { + output->normal = -normal; + } + else + { + output->normal = normal; + } + return true; +} + +void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 v1 = b2Mul(xf, m_vertex1); + b2Vec2 v2 = b2Mul(xf, m_vertex2); + + b2Vec2 lower = b2Min(v1, v2); + b2Vec2 upper = b2Max(v1, v2); + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center = 0.5f * (m_vertex1 + m_vertex2); + massData->I = 0.0f; +} diff --git a/external/box2d/Collision/Shapes/b2EdgeShape.h b/external/box2d/Collision/Shapes/b2EdgeShape.h new file mode 100644 index 0000000000..6163bcbf1c --- /dev/null +++ b/external/box2d/Collision/Shapes/b2EdgeShape.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2006-2010 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. +*/ + +#ifndef B2_EDGE_SHAPE_H +#define B2_EDGE_SHAPE_H + +#include + +/// A line segment (edge) shape. These can be connected in chains or loops +/// to other edge shapes. The connectivity information is used to ensure +/// correct contact normals. +class b2EdgeShape : public b2Shape +{ +public: + b2EdgeShape(); + + /// Set this as an isolated edge. + void Set(const b2Vec2& v1, const b2Vec2& v2); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// These are the edge vertices + b2Vec2 m_vertex1, m_vertex2; + + /// Optional adjacent vertices. These are used for smooth collision. + b2Vec2 m_vertex0, m_vertex3; + bool m_hasVertex0, m_hasVertex3; +}; + +inline b2EdgeShape::b2EdgeShape() +{ + m_type = e_edge; + m_radius = b2_polygonRadius; + m_vertex0.x = 0.0f; + m_vertex0.y = 0.0f; + m_vertex3.x = 0.0f; + m_vertex3.y = 0.0f; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +#endif diff --git a/external/box2d/Collision/Shapes/b2PolygonShape.cpp b/external/box2d/Collision/Shapes/b2PolygonShape.cpp new file mode 100644 index 0000000000..c04c1dc49b --- /dev/null +++ b/external/box2d/Collision/Shapes/b2PolygonShape.cpp @@ -0,0 +1,361 @@ +/* +* Copyright (c) 2006-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 +#include + +b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2PolygonShape)); + b2PolygonShape* clone = new (mem) b2PolygonShape; + *clone = *this; + return clone; +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid.SetZero(); +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid = center; + + b2Transform xf; + xf.p = center; + xf.q.Set(angle); + + // Transform vertices and normals. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = b2Mul(xf, m_vertices[i]); + m_normals[i] = b2Mul(xf.q, m_normals[i]); + } +} + +int32 b2PolygonShape::GetChildCount() const +{ + return 1; +} + +static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) +{ + b2Assert(count >= 3); + + b2Vec2 c; c.Set(0.0f, 0.0f); + float32 area = 0.0f; + + // pRef is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 pRef(0.0f, 0.0f); +#if 0 + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < count; ++i) + { + pRef += vs[i]; + } + pRef *= 1.0f / count; +#endif + + const float32 inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < count; ++i) + { + // Triangle vertices. + b2Vec2 p1 = pRef; + b2Vec2 p2 = vs[i]; + b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; + + b2Vec2 e1 = p2 - p1; + b2Vec2 e2 = p3 - p1; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + c += triangleArea * inv3 * (p1 + p2 + p3); + } + + // Centroid + b2Assert(area > b2_epsilon); + c *= 1.0f / area; + return c; +} + +void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) +{ + b2Assert(3 <= count && count <= b2_maxPolygonVertices); + m_vertexCount = count; + + // Copy vertices. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = vertices[i]; + } + + // Compute normals. Ensure the edges have non-zero length. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); + m_normals[i] = b2Cross(edge, 1.0f); + m_normals[i].Normalize(); + } + +#ifdef _DEBUG + // Ensure the polygon is convex and the interior + // is to the left of each edge. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + + for (int32 j = 0; j < m_vertexCount; ++j) + { + // Don't check vertices on the current edge. + if (j == i1 || j == i2) + { + continue; + } + + b2Vec2 r = m_vertices[j] - m_vertices[i1]; + + // If this crashes, your polygon is non-convex, has colinear edges, + // or the winding order is wrong. + float32 s = b2Cross(edge, r); + b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order"); + } + } +#endif + + // Compute the polygon centroid. + m_centroid = ComputeCentroid(m_vertices, m_vertexCount); +} + +bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); + + for (int32 i = 0; i < m_vertexCount; ++i) + { + float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); + if (dot > 0.0f) + { + return false; + } + } + + return true; +} + +bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the polygon's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + float32 lower = 0.0f, upper = input.maxFraction; + + int32 index = -1; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // p = p1 + a * d + // dot(normal, p - v) = 0 + // dot(normal, p1 - v) + a * dot(normal, d) = 0 + float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); + float32 denominator = b2Dot(m_normals[i], d); + + if (denominator == 0.0f) + { + if (numerator < 0.0f) + { + return false; + } + } + else + { + // Note: we want this predicate without division: + // lower < numerator / denominator, where denominator < 0 + // Since denominator < 0, we have to flip the inequality: + // lower < numerator / denominator <==> denominator * lower > numerator. + if (denominator < 0.0f && numerator < lower * denominator) + { + // Increase lower. + // The segment enters this half-space. + lower = numerator / denominator; + index = i; + } + else if (denominator > 0.0f && numerator < upper * denominator) + { + // Decrease upper. + // The segment exits this half-space. + upper = numerator / denominator; + } + } + + // The use of epsilon here causes the assert on lower to trip + // in some cases. Apparently the use of epsilon was to make edge + // shapes work, but now those are handled separately. + //if (upper < lower - b2_epsilon) + if (upper < lower) + { + return false; + } + } + + b2Assert(0.0f <= lower && lower <= input.maxFraction); + + if (index >= 0) + { + output->fraction = lower; + output->normal = b2Mul(xf.q, m_normals[index]); + return true; + } + + return false; +} + +void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 lower = b2Mul(xf, m_vertices[0]); + b2Vec2 upper = lower; + + for (int32 i = 1; i < m_vertexCount; ++i) + { + b2Vec2 v = b2Mul(xf, m_vertices[i]); + lower = b2Min(lower, v); + upper = b2Max(upper, v); + } + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const +{ + // Polygon mass, centroid, and inertia. + // Let rho be the polygon density in mass per unit area. + // Then: + // mass = rho * int(dA) + // centroid.x = (1/mass) * rho * int(x * dA) + // centroid.y = (1/mass) * rho * int(y * dA) + // I = rho * int((x*x + y*y) * dA) + // + // We can compute these integrals by summing all the integrals + // for each triangle of the polygon. To evaluate the integral + // for a single triangle, we make a change of variables to + // the (u,v) coordinates of the triangle: + // x = x0 + e1x * u + e2x * v + // y = y0 + e1y * u + e2y * v + // where 0 <= u && 0 <= v && u + v <= 1. + // + // We integrate u from [0,1-v] and then v from [0,1]. + // We also need to use the Jacobian of the transformation: + // D = cross(e1, e2) + // + // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) + // + // The rest of the derivation is handled by computer algebra. + + b2Assert(m_vertexCount >= 3); + + b2Vec2 center; center.Set(0.0f, 0.0f); + float32 area = 0.0f; + float32 I = 0.0f; + + // s is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 s(0.0f, 0.0f); + + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < m_vertexCount; ++i) + { + s += m_vertices[i]; + } + s *= 1.0f / m_vertexCount; + + const float32 k_inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // Triangle vertices. + b2Vec2 e1 = m_vertices[i] - s; + b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + center += triangleArea * k_inv3 * (e1 + e2); + + float32 ex1 = e1.x, ey1 = e1.y; + float32 ex2 = e2.x, ey2 = e2.y; + + float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; + float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; + + I += (0.25f * k_inv3 * D) * (intx2 + inty2); + } + + // Total mass + massData->mass = density * area; + + // Center of mass + b2Assert(area > b2_epsilon); + center *= 1.0f / area; + massData->center = center + s; + + // Inertia tensor relative to the local origin (point s). + massData->I = density * I; + + // Shift to center of mass then to original body origin. + massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); +} diff --git a/external/box2d/Collision/Shapes/b2PolygonShape.h b/external/box2d/Collision/Shapes/b2PolygonShape.h new file mode 100644 index 0000000000..70daccb2ff --- /dev/null +++ b/external/box2d/Collision/Shapes/b2PolygonShape.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_SHAPE_H +#define B2_POLYGON_SHAPE_H + +#include + +/// A convex polygon. It is assumed that the interior of the polygon is to +/// the left of each edge. +/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. +/// In most cases you should not need many vertices for a convex polygon. +class b2PolygonShape : public b2Shape +{ +public: + b2PolygonShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Copy vertices. This assumes the vertices define a convex polygon. + /// It is assumed that the exterior is the the right of each edge. + /// The count must be in the range [3, b2_maxPolygonVertices]. + void Set(const b2Vec2* vertices, int32 vertexCount); + + /// Build vertices to represent an axis-aligned box. + /// @param hx the half-width. + /// @param hy the half-height. + void SetAsBox(float32 hx, float32 hy); + + /// Build vertices to represent an oriented box. + /// @param hx the half-width. + /// @param hy the half-height. + /// @param center the center of the box in local coordinates. + /// @param angle the rotation of the box in local coordinates. + void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return m_vertexCount; } + + /// Get a vertex by index. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_centroid; + b2Vec2 m_vertices[b2_maxPolygonVertices]; + b2Vec2 m_normals[b2_maxPolygonVertices]; + int32 m_vertexCount; +}; + +inline b2PolygonShape::b2PolygonShape() +{ + m_type = e_polygon; + m_radius = b2_polygonRadius; + m_vertexCount = 0; + m_centroid.SetZero(); +} + +inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_vertexCount); + return m_vertices[index]; +} + +#endif diff --git a/external/box2d/Collision/Shapes/b2Shape.h b/external/box2d/Collision/Shapes/b2Shape.h new file mode 100644 index 0000000000..2e2aedd14a --- /dev/null +++ b/external/box2d/Collision/Shapes/b2Shape.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_SHAPE_H +#define B2_SHAPE_H + +#include +#include +#include + +/// This holds the mass data computed for a shape. +struct b2MassData +{ + /// The mass of the shape, usually in kilograms. + float32 mass; + + /// The position of the shape's centroid relative to the shape's origin. + b2Vec2 center; + + /// The rotational inertia of the shape about the local origin. + float32 I; +}; + +/// A shape is used for collision detection. You can create a shape however you like. +/// Shapes used for simulation in b2World are created automatically when a b2Fixture +/// is created. Shapes may encapsulate a one or more child shapes. +class b2Shape +{ +public: + + enum Type + { + e_circle = 0, + e_edge = 1, + e_polygon = 2, + e_chain = 3, + e_typeCount = 4 + }; + + virtual ~b2Shape() {} + + /// Clone the concrete shape using the provided allocator. + virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; + + /// Get the type of this shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + Type GetType() const; + + /// Get the number of child primitives. + virtual int32 GetChildCount() const = 0; + + /// Test a point for containment in this shape. This only works for convex shapes. + /// @param xf the shape world transform. + /// @param p a point in world coordinates. + virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; + + /// Cast a ray against a child shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + /// @param transform the transform to be applied to the shape. + /// @param childIndex the child shape index + virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const = 0; + + /// Given a transform, compute the associated axis aligned bounding box for a child shape. + /// @param aabb returns the axis aligned box. + /// @param xf the world transform of the shape. + /// @param childIndex the child shape + virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; + + /// Compute the mass properties of this shape using its dimensions and density. + /// The inertia tensor is computed about the local origin. + /// @param massData returns the mass data for this shape. + /// @param density the density in kilograms per meter squared. + virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; + + Type m_type; + float32 m_radius; +}; + +inline b2Shape::Type b2Shape::GetType() const +{ + return m_type; +} + +#endif diff --git a/external/box2d/Collision/b2BroadPhase.cpp b/external/box2d/Collision/b2BroadPhase.cpp new file mode 100644 index 0000000000..431f6de1ee --- /dev/null +++ b/external/box2d/Collision/b2BroadPhase.cpp @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2006-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 +#include +using namespace std; + +b2BroadPhase::b2BroadPhase() +{ + m_proxyCount = 0; + + m_pairCapacity = 16; + m_pairCount = 0; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + + m_moveCapacity = 16; + m_moveCount = 0; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); +} + +b2BroadPhase::~b2BroadPhase() +{ + b2Free(m_moveBuffer); + b2Free(m_pairBuffer); +} + +int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = m_tree.CreateProxy(aabb, userData); + ++m_proxyCount; + BufferMove(proxyId); + return proxyId; +} + +void b2BroadPhase::DestroyProxy(int32 proxyId) +{ + UnBufferMove(proxyId); + --m_proxyCount; + m_tree.DestroyProxy(proxyId); +} + +void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); + if (buffer) + { + BufferMove(proxyId); + } +} + +void b2BroadPhase::TouchProxy(int32 proxyId) +{ + BufferMove(proxyId); +} + +void b2BroadPhase::BufferMove(int32 proxyId) +{ + if (m_moveCount == m_moveCapacity) + { + int32* oldBuffer = m_moveBuffer; + m_moveCapacity *= 2; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); + memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); + b2Free(oldBuffer); + } + + m_moveBuffer[m_moveCount] = proxyId; + ++m_moveCount; +} + +void b2BroadPhase::UnBufferMove(int32 proxyId) +{ + for (int32 i = 0; i < m_moveCount; ++i) + { + if (m_moveBuffer[i] == proxyId) + { + m_moveBuffer[i] = e_nullProxy; + return; + } + } +} + +// This is called from b2DynamicTree::Query when we are gathering pairs. +bool b2BroadPhase::QueryCallback(int32 proxyId) +{ + // A proxy cannot form a pair with itself. + if (proxyId == m_queryProxyId) + { + return true; + } + + // Grow the pair buffer as needed. + if (m_pairCount == m_pairCapacity) + { + b2Pair* oldBuffer = m_pairBuffer; + m_pairCapacity *= 2; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); + b2Free(oldBuffer); + } + + m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); + m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); + ++m_pairCount; + + return true; +} diff --git a/external/box2d/Collision/b2BroadPhase.h b/external/box2d/Collision/b2BroadPhase.h new file mode 100644 index 0000000000..cf2414730a --- /dev/null +++ b/external/box2d/Collision/b2BroadPhase.h @@ -0,0 +1,248 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_BROAD_PHASE_H +#define B2_BROAD_PHASE_H + +#include +#include +#include +#include + +struct b2Pair +{ + int32 proxyIdA; + int32 proxyIdB; + int32 next; +}; + +/// The broad-phase is used for computing pairs and performing volume queries and ray casts. +/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. +/// It is up to the client to consume the new pairs and to track subsequent overlap. +class b2BroadPhase +{ +public: + + enum + { + e_nullProxy = -1 + }; + + b2BroadPhase(); + ~b2BroadPhase(); + + /// Create a proxy with an initial AABB. Pairs are not reported until + /// UpdatePairs is called. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. It is up to the client to remove any pairs. + void DestroyProxy(int32 proxyId); + + /// Call MoveProxy as many times as you like, then when you are done + /// call UpdatePairs to finalized the proxy pairs (for your time step). + void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); + + /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. + void TouchProxy(int32 proxyId); + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Get user data from a proxy. Returns NULL if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Test overlap of fat AABBs. + bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; + + /// Get the number of proxies. + int32 GetProxyCount() const; + + /// Update the pairs. This results in pair callbacks. This can only add pairs. + template + void UpdatePairs(T* callback); + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Get the height of the embedded tree. + int32 GetTreeHeight() const; + + /// Get the balance of the embedded tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the embedded tree. + float32 GetTreeQuality() const; + +private: + + friend class b2DynamicTree; + + void BufferMove(int32 proxyId); + void UnBufferMove(int32 proxyId); + + bool QueryCallback(int32 proxyId); + + b2DynamicTree m_tree; + + int32 m_proxyCount; + + int32* m_moveBuffer; + int32 m_moveCapacity; + int32 m_moveCount; + + b2Pair* m_pairBuffer; + int32 m_pairCapacity; + int32 m_pairCount; + + int32 m_queryProxyId; +}; + +/// This is used to sort pairs. +inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) +{ + if (pair1.proxyIdA < pair2.proxyIdA) + { + return true; + } + + if (pair1.proxyIdA == pair2.proxyIdA) + { + return pair1.proxyIdB < pair2.proxyIdB; + } + + return false; +} + +inline void* b2BroadPhase::GetUserData(int32 proxyId) const +{ + return m_tree.GetUserData(proxyId); +} + +inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const +{ + const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); + const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); + return b2TestOverlap(aabbA, aabbB); +} + +inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const +{ + return m_tree.GetFatAABB(proxyId); +} + +inline int32 b2BroadPhase::GetProxyCount() const +{ + return m_proxyCount; +} + +inline int32 b2BroadPhase::GetTreeHeight() const +{ + return m_tree.GetHeight(); +} + +inline int32 b2BroadPhase::GetTreeBalance() const +{ + return m_tree.GetMaxBalance(); +} + +inline float32 b2BroadPhase::GetTreeQuality() const +{ + return m_tree.GetAreaRatio(); +} + +template +void b2BroadPhase::UpdatePairs(T* callback) +{ + // Reset pair buffer + m_pairCount = 0; + + // Perform tree queries for all moving proxies. + for (int32 i = 0; i < m_moveCount; ++i) + { + m_queryProxyId = m_moveBuffer[i]; + if (m_queryProxyId == e_nullProxy) + { + continue; + } + + // We have to query the tree with the fat AABB so that + // we don't fail to create a pair that may touch later. + const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); + + // Query tree, create pairs and add them pair buffer. + m_tree.Query(this, fatAABB); + } + + // Reset move buffer + m_moveCount = 0; + + // Sort the pair buffer to expose duplicates. + std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); + + // Send the pairs back to the client. + int32 i = 0; + while (i < m_pairCount) + { + b2Pair* primaryPair = m_pairBuffer + i; + void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); + void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); + + callback->AddPair(userDataA, userDataB); + ++i; + + // Skip any duplicate pairs. + while (i < m_pairCount) + { + b2Pair* pair = m_pairBuffer + i; + if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) + { + break; + } + ++i; + } + } + + // Try to keep the tree balanced. + //m_tree.Rebalance(4); +} + +template +inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const +{ + m_tree.Query(callback, aabb); +} + +template +inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const +{ + m_tree.RayCast(callback, input); +} + +#endif diff --git a/external/box2d/Collision/b2CollideCircle.cpp b/external/box2d/Collision/b2CollideCircle.cpp new file mode 100644 index 0000000000..ed561eb04b --- /dev/null +++ b/external/box2d/Collision/b2CollideCircle.cpp @@ -0,0 +1,154 @@ +/* +* 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 +#include +#include + +void b2CollideCircles( + b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + b2Vec2 pA = b2Mul(xfA, circleA->m_p); + b2Vec2 pB = b2Mul(xfB, circleB->m_p); + + b2Vec2 d = pB - pA; + float32 distSqr = b2Dot(d, d); + float32 rA = circleA->m_radius, rB = circleB->m_radius; + float32 radius = rA + rB; + if (distSqr > radius * radius) + { + return; + } + + manifold->type = b2Manifold::e_circles; + manifold->localPoint = circleA->m_p; + manifold->localNormal.SetZero(); + manifold->pointCount = 1; + + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; +} + +void b2CollidePolygonAndCircle( + b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + // Compute circle position in the frame of the polygon. + b2Vec2 c = b2Mul(xfB, circleB->m_p); + b2Vec2 cLocal = b2MulT(xfA, c); + + // Find the min separating edge. + int32 normalIndex = 0; + float32 separation = -b2_maxFloat; + float32 radius = polygonA->m_radius + circleB->m_radius; + int32 vertexCount = polygonA->m_vertexCount; + const b2Vec2* vertices = polygonA->m_vertices; + const b2Vec2* normals = polygonA->m_normals; + + for (int32 i = 0; i < vertexCount; ++i) + { + float32 s = b2Dot(normals[i], cLocal - vertices[i]); + + if (s > radius) + { + // Early out. + return; + } + + if (s > separation) + { + separation = s; + normalIndex = i; + } + } + + // Vertices that subtend the incident face. + int32 vertIndex1 = normalIndex; + int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; + b2Vec2 v1 = vertices[vertIndex1]; + b2Vec2 v2 = vertices[vertIndex2]; + + // If the center is inside the polygon ... + if (separation < b2_epsilon) + { + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[normalIndex]; + manifold->localPoint = 0.5f * (v1 + v2); + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + return; + } + + // Compute barycentric coordinates + float32 u1 = b2Dot(cLocal - v1, v2 - v1); + float32 u2 = b2Dot(cLocal - v2, v1 - v2); + if (u1 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v1) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v1; + manifold->localNormal.Normalize(); + manifold->localPoint = v1; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else if (u2 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v2) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v2; + manifold->localNormal.Normalize(); + manifold->localPoint = v2; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else + { + b2Vec2 faceCenter = 0.5f * (v1 + v2); + float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); + if (separation > radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[vertIndex1]; + manifold->localPoint = faceCenter; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } +} diff --git a/external/box2d/Collision/b2CollideEdge.cpp b/external/box2d/Collision/b2CollideEdge.cpp new file mode 100644 index 0000000000..96ca71dccc --- /dev/null +++ b/external/box2d/Collision/b2CollideEdge.cpp @@ -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 +#include +#include +#include + + +// 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 hasVertex3F = 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 (hasVertex3F) + { + 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 && hasVertex3F) + { + 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 (hasVertex3F) + { + 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 = 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 = 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 = 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 = 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); +} diff --git a/external/box2d/Collision/b2CollidePolygon.cpp b/external/box2d/Collision/b2CollidePolygon.cpp new file mode 100644 index 0000000000..be2518d966 --- /dev/null +++ b/external/box2d/Collision/b2CollidePolygon.cpp @@ -0,0 +1,317 @@ +/* +* Copyright (c) 2006-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 +#include + +// Find the separation between poly1 and poly2 for a give edge normal on poly1. +static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* vertices1 = poly1->m_vertices; + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Convert normal from poly1's frame into poly2's frame. + b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); + b2Vec2 normal1 = b2MulT(xf2.q, normal1World); + + // Find support vertex on poly2 for -normal. + int32 index = 0; + float32 minDot = b2_maxFloat; + + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(vertices2[i], normal1); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); + b2Vec2 v2 = b2Mul(xf2, vertices2[index]); + float32 separation = b2Dot(v2 - v1, normal1World); + return separation; +} + +// Find the max separation between poly1 and poly2 using edge normals from poly1. +static float32 b2FindMaxSeparation(int32* edgeIndex, + const b2PolygonShape* poly1, const b2Transform& xf1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + int32 count1 = poly1->m_vertexCount; + const b2Vec2* normals1 = poly1->m_normals; + + // Vector pointing from the centroid of poly1 to the centroid of poly2. + b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); + b2Vec2 dLocal1 = b2MulT(xf1.q, d); + + // Find edge normal on poly1 that has the largest projection onto d. + int32 edge = 0; + float32 maxDot = -b2_maxFloat; + for (int32 i = 0; i < count1; ++i) + { + float32 dot = b2Dot(normals1[i], dLocal1); + if (dot > maxDot) + { + maxDot = dot; + edge = i; + } + } + + // Get the separation for the edge normal. + float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + // Check the separation for the previous edge normal. + int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; + float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + + // Check the separation for the next edge normal. + int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; + float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + + // Find the best edge and the search direction. + int32 bestEdge; + float32 bestSeparation; + int32 increment; + if (sPrev > s && sPrev > sNext) + { + increment = -1; + bestEdge = prevEdge; + bestSeparation = sPrev; + } + else if (sNext > s) + { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext; + } + else + { + *edgeIndex = edge; + return s; + } + + // Perform a local search for the best edge normal. + for ( ; ; ) + { + if (increment == -1) + edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; + else + edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; + + s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + if (s > bestSeparation) + { + bestEdge = edge; + bestSeparation = s; + } + else + { + break; + } + } + + *edgeIndex = bestEdge; + return bestSeparation; +} + +static void b2FindIncidentEdge(b2ClipVertex c[2], + const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + const b2Vec2* normals2 = poly2->m_normals; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Get the normal of the reference edge in poly2's frame. + b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); + + // Find the incident edge on poly2. + int32 index = 0; + float32 minDot = b2_maxFloat; + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(normal1, normals2[i]); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + // Build the clip vertices for the incident edge. + int32 i1 = index; + int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; + + c[0].v = b2Mul(xf2, vertices2[i1]); + c[0].id.cf.indexA = (uint8)edge1; + c[0].id.cf.indexB = (uint8)i1; + c[0].id.cf.typeA = b2ContactFeature::e_face; + c[0].id.cf.typeB = b2ContactFeature::e_vertex; + + c[1].v = b2Mul(xf2, vertices2[i2]); + c[1].id.cf.indexA = (uint8)edge1; + c[1].id.cf.indexB = (uint8)i2; + c[1].id.cf.typeA = b2ContactFeature::e_face; + c[1].id.cf.typeB = b2ContactFeature::e_vertex; +} + +// Find edge normal of max separation on A - return if separating axis is found +// Find edge normal of max separation on B - return if separation axis is found +// Choose reference edge as min(minA, minB) +// Find incident edge +// Clip + +// The normal points from 1 to 2 +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polyA, const b2Transform& xfA, + const b2PolygonShape* polyB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + float32 totalRadius = polyA->m_radius + polyB->m_radius; + + int32 edgeA = 0; + float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); + if (separationA > totalRadius) + return; + + int32 edgeB = 0; + float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); + if (separationB > totalRadius) + return; + + const b2PolygonShape* poly1; // reference polygon + const b2PolygonShape* poly2; // incident polygon + b2Transform xf1, xf2; + int32 edge1; // reference edge + uint8 flip; + const float32 k_relativeTol = 0.98f; + const float32 k_absoluteTol = 0.001f; + + if (separationB > k_relativeTol * separationA + k_absoluteTol) + { + poly1 = polyB; + poly2 = polyA; + xf1 = xfB; + xf2 = xfA; + edge1 = edgeB; + manifold->type = b2Manifold::e_faceB; + flip = 1; + } + else + { + poly1 = polyA; + poly2 = polyB; + xf1 = xfA; + xf2 = xfB; + edge1 = edgeA; + manifold->type = b2Manifold::e_faceA; + flip = 0; + } + + b2ClipVertex incidentEdge[2]; + b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + + int32 count1 = poly1->m_vertexCount; + const b2Vec2* vertices1 = poly1->m_vertices; + + int32 iv1 = edge1; + int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; + + b2Vec2 v11 = vertices1[iv1]; + b2Vec2 v12 = vertices1[iv2]; + + b2Vec2 localTangent = v12 - v11; + localTangent.Normalize(); + + b2Vec2 localNormal = b2Cross(localTangent, 1.0f); + b2Vec2 planePoint = 0.5f * (v11 + v12); + + b2Vec2 tangent = b2Mul(xf1.q, localTangent); + b2Vec2 normal = b2Cross(tangent, 1.0f); + + v11 = b2Mul(xf1, v11); + v12 = b2Mul(xf1, v12); + + // Face offset. + float32 frontOffset = b2Dot(normal, v11); + + // Side offsets, extended by polytope skin thickness. + float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; + float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; + + // Clip incident edge against extruded edge1 side edges. + b2ClipVertex clipPoints1[2]; + b2ClipVertex clipPoints2[2]; + int np; + + // Clip to box side 1 + np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); + + if (np < 2) + return; + + // Clip to negative box side 1 + np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); + + if (np < 2) + { + return; + } + + // Now clipPoints2 contains the clipped points. + manifold->localNormal = localNormal; + manifold->localPoint = planePoint; + + int32 pointCount = 0; + for (int32 i = 0; i < b2_maxManifoldPoints; ++i) + { + float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; + + if (separation <= totalRadius) + { + b2ManifoldPoint* cp = manifold->points + pointCount; + cp->localPoint = b2MulT(xf2, clipPoints2[i].v); + cp->id = clipPoints2[i].id; + if (flip) + { + // Swap features + b2ContactFeature cf = cp->id.cf; + cp->id.cf.indexA = cf.indexB; + cp->id.cf.indexB = cf.indexA; + cp->id.cf.typeA = cf.typeB; + cp->id.cf.typeB = cf.typeA; + } + ++pointCount; + } + } + + manifold->pointCount = pointCount; +} diff --git a/external/box2d/Collision/b2Collision.cpp b/external/box2d/Collision/b2Collision.cpp new file mode 100644 index 0000000000..2dd5ff0ab6 --- /dev/null +++ b/external/box2d/Collision/b2Collision.cpp @@ -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 +#include + +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 = 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; +} diff --git a/external/box2d/Collision/b2Collision.h b/external/box2d/Collision/b2Collision.h new file mode 100644 index 0000000000..2e7386232b --- /dev/null +++ b/external/box2d/Collision/b2Collision.h @@ -0,0 +1,276 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_COLLISION_H +#define B2_COLLISION_H + +#include +#include + +/// @file +/// Structures and functions used for computing contact points, distance +/// queries, and TOI queries. + +class b2Shape; +class b2CircleShape; +class b2EdgeShape; +class b2PolygonShape; + +const uint8 b2_nullFeature = UCHAR_MAX; + +/// The features that intersect to form the contact point +/// This must be 4 bytes or less. +struct b2ContactFeature +{ + enum Type + { + e_vertex = 0, + e_face = 1 + }; + + uint8 indexA; ///< Feature index on shapeA + uint8 indexB; ///< Feature index on shapeB + uint8 typeA; ///< The feature type on shapeA + uint8 typeB; ///< The feature type on shapeB +}; + +/// Contact ids to facilitate warm starting. +union b2ContactID +{ + b2ContactFeature cf; + uint32 key; ///< Used to quickly compare contact ids. +}; + +/// A manifold point is a contact point belonging to a contact +/// manifold. It holds details related to the geometry and dynamics +/// of the contact points. +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleB +/// -e_faceA: the local center of cirlceB or the clip point of polygonB +/// -e_faceB: the clip point of polygonA +/// This structure is stored across time steps, so we keep it small. +/// Note: the impulses are used for internal caching and may not +/// provide reliable contact forces, especially for high speed collisions. +struct b2ManifoldPoint +{ + b2Vec2 localPoint; ///< usage depends on manifold type + float32 normalImpulse; ///< the non-penetration impulse + float32 tangentImpulse; ///< the friction impulse + b2ContactID id; ///< uniquely identifies a contact point between two shapes +}; + +/// A manifold for two touching convex shapes. +/// Box2D supports multiple types of contact: +/// - clip point versus plane with radius +/// - point versus point with radius (circles) +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleA +/// -e_faceA: the center of faceA +/// -e_faceB: the center of faceB +/// Similarly the local normal usage: +/// -e_circles: not used +/// -e_faceA: the normal on polygonA +/// -e_faceB: the normal on polygonB +/// We store contacts in this way so that position correction can +/// account for movement, which is critical for continuous physics. +/// All contact scenarios must be expressed in one of these types. +/// This structure is stored across time steps, so we keep it small. +struct b2Manifold +{ + enum Type + { + e_circles, + e_faceA, + e_faceB + }; + + b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact + b2Vec2 localNormal; ///< not use for Type::e_points + b2Vec2 localPoint; ///< usage depends on manifold type + Type type; + int32 pointCount; ///< the number of manifold points +}; + +/// This is used to compute the current state of a contact manifold. +struct b2WorldManifold +{ + /// Evaluate the manifold with supplied transforms. This assumes + /// modest motion from the original state. This does not change the + /// point count, impulses, etc. The radii must come from the shapes + /// that generated the manifold. + void Initialize(const b2Manifold* manifold, + const b2Transform& xfA, float32 radiusA, + const b2Transform& xfB, float32 radiusB); + + b2Vec2 normal; ///< world vector pointing from A to B + b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) +}; + +/// This is used for determining the state of contact points. +enum b2PointState +{ + b2_nullState, ///< point does not exist + b2_addState, ///< point was added in the update + b2_persistState, ///< point persisted across the update + b2_removeState ///< point was removed in the update +}; + +/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 +/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. +void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], + const b2Manifold* manifold1, const b2Manifold* manifold2); + +/// Used for computing contact manifolds. +struct b2ClipVertex +{ + b2Vec2 v; + b2ContactID id; +}; + +/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). +struct b2RayCastInput +{ + b2Vec2 p1, p2; + float32 maxFraction; +}; + +/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 +/// come from b2RayCastInput. +struct b2RayCastOutput +{ + b2Vec2 normal; + float32 fraction; +}; + +/// An axis aligned bounding box. +struct b2AABB +{ + /// Verify that the bounds are sorted. + bool IsValid() const; + + /// Get the center of the AABB. + b2Vec2 GetCenter() const + { + return 0.5f * (lowerBound + upperBound); + } + + /// Get the extents of the AABB (half-widths). + b2Vec2 GetExtents() const + { + return 0.5f * (upperBound - lowerBound); + } + + /// Get the perimeter length + float32 GetPerimeter() const + { + float32 wx = upperBound.x - lowerBound.x; + float32 wy = upperBound.y - lowerBound.y; + return 2.0f * (wx + wy); + } + + /// Combine an AABB into this one. + void Combine(const b2AABB& aabb) + { + lowerBound = b2Min(lowerBound, aabb.lowerBound); + upperBound = b2Max(upperBound, aabb.upperBound); + } + + /// Combine two AABBs into this one. + void Combine(const b2AABB& aabb1, const b2AABB& aabb2) + { + lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); + upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); + } + + /// Does this aabb contain the provided AABB. + bool Contains(const b2AABB& aabb) const + { + bool result = true; + result = result && lowerBound.x <= aabb.lowerBound.x; + result = result && lowerBound.y <= aabb.lowerBound.y; + result = result && aabb.upperBound.x <= upperBound.x; + result = result && aabb.upperBound.y <= upperBound.y; + return result; + } + + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; + + b2Vec2 lowerBound; ///< the lower vertex + b2Vec2 upperBound; ///< the upper vertex +}; + +/// Compute the collision manifold between two circles. +void b2CollideCircles(b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between a polygon and a circle. +void b2CollidePolygonAndCircle(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between two polygons. +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndCircle(b2Manifold* manifold, + const b2EdgeShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndPolygon(b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* circleB, const b2Transform& xfB); + +/// Clipping for contact manifolds. +int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], + const b2Vec2& normal, float32 offset, int32 vertexIndexA); + +/// Determine if two generic shapes overlap. +bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, + const b2Shape* shapeB, int32 indexB, + const b2Transform& xfA, const b2Transform& xfB); + +// ---------------- Inline Functions ------------------------------------------ + +inline bool b2AABB::IsValid() const +{ + b2Vec2 d = upperBound - lowerBound; + bool valid = d.x >= 0.0f && d.y >= 0.0f; + valid = valid && lowerBound.IsValid() && upperBound.IsValid(); + return valid; +} + +inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) +{ + b2Vec2 d1, d2; + d1 = b.lowerBound - a.upperBound; + d2 = a.lowerBound - b.upperBound; + + if (d1.x > 0.0f || d1.y > 0.0f) + return false; + + if (d2.x > 0.0f || d2.y > 0.0f) + return false; + + return true; +} + +#endif diff --git a/external/box2d/Collision/b2Distance.cpp b/external/box2d/Collision/b2Distance.cpp new file mode 100644 index 0000000000..ac67d3be43 --- /dev/null +++ b/external/box2d/Collision/b2Distance.cpp @@ -0,0 +1,603 @@ +/* +* 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 +#include +#include +#include +#include + +// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. +int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + +void b2DistanceProxy::Set(const b2Shape* shape, int32 index) +{ + switch (shape->GetType()) + { + case b2Shape::e_circle: + { + const b2CircleShape* circle = (b2CircleShape*)shape; + m_vertices = &circle->m_p; + m_count = 1; + m_radius = circle->m_radius; + } + break; + + case b2Shape::e_polygon: + { + const b2PolygonShape* polygon = (b2PolygonShape*)shape; + m_vertices = polygon->m_vertices; + m_count = polygon->m_vertexCount; + m_radius = polygon->m_radius; + } + break; + + case b2Shape::e_chain: + { + const b2ChainShape* chain = (b2ChainShape*)shape; + b2Assert(0 <= index && index < chain->m_count); + + m_buffer[0] = chain->m_vertices[index]; + if (index + 1 < chain->m_count) + { + m_buffer[1] = chain->m_vertices[index + 1]; + } + else + { + m_buffer[1] = chain->m_vertices[0]; + } + + m_vertices = m_buffer; + m_count = 2; + m_radius = chain->m_radius; + } + break; + + case b2Shape::e_edge: + { + const b2EdgeShape* edge = (b2EdgeShape*)shape; + m_vertices = &edge->m_vertex1; + m_count = 2; + m_radius = edge->m_radius; + } + break; + + default: + b2Assert(false); + } +} + + +struct b2SimplexVertex +{ + b2Vec2 wA; // support point in proxyA + b2Vec2 wB; // support point in proxyB + b2Vec2 w; // wB - wA + float32 a; // barycentric coordinate for closest point + int32 indexA; // wA index + int32 indexB; // wB index +}; + +struct b2Simplex +{ + void ReadCache( const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Transform& transformA, + const b2DistanceProxy* proxyB, const b2Transform& transformB) + { + b2Assert(cache->count <= 3); + + // Copy data from cache. + m_count = cache->count; + b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + b2SimplexVertex* v = vertices + i; + v->indexA = cache->indexA[i]; + v->indexB = cache->indexB[i]; + b2Vec2 wALocal = proxyA->GetVertex(v->indexA); + b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + v->a = 0.0f; + } + + // Compute the new simplex metric, if it is substantially different than + // old metric then flush the simplex. + if (m_count > 1) + { + float32 metric1 = cache->metric; + float32 metric2 = GetMetric(); + if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) + { + // Reset the simplex. + m_count = 0; + } + } + + // If the cache is empty or invalid ... + if (m_count == 0) + { + b2SimplexVertex* v = vertices + 0; + v->indexA = 0; + v->indexB = 0; + b2Vec2 wALocal = proxyA->GetVertex(0); + b2Vec2 wBLocal = proxyB->GetVertex(0); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + m_count = 1; + } + } + + void WriteCache(b2SimplexCache* cache) const + { + cache->metric = GetMetric(); + cache->count = uint16(m_count); + const b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + cache->indexA[i] = uint8(vertices[i].indexA); + cache->indexB[i] = uint8(vertices[i].indexB); + } + } + + b2Vec2 GetSearchDirection() const + { + switch (m_count) + { + case 1: + return -m_v1.w; + + case 2: + { + b2Vec2 e12 = m_v2.w - m_v1.w; + float32 sgn = b2Cross(e12, -m_v1.w); + if (sgn > 0.0f) + { + // Origin is left of e12. + return b2Cross(1.0f, e12); + } + else + { + // Origin is right of e12. + return b2Cross(e12, 1.0f); + } + } + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + b2Vec2 GetClosestPoint() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return b2Vec2_zero; + + case 1: + return m_v1.w; + + case 2: + return m_v1.a * m_v1.w + m_v2.a * m_v2.w; + + case 3: + return b2Vec2_zero; + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const + { + switch (m_count) + { + case 0: + b2Assert(false); + break; + + case 1: + *pA = m_v1.wA; + *pB = m_v1.wB; + break; + + case 2: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; + *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; + break; + + case 3: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; + *pB = *pA; + break; + + default: + b2Assert(false); + break; + } + } + + float32 GetMetric() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return 0.0; + + case 1: + return 0.0f; + + case 2: + return b2Distance(m_v1.w, m_v2.w); + + case 3: + return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); + + default: + b2Assert(false); + return 0.0f; + } + } + + void Solve2(); + void Solve3(); + + b2SimplexVertex m_v1, m_v2, m_v3; + int32 m_count; +}; + + +// Solve a line segment using barycentric coordinates. +// +// p = a1 * w1 + a2 * w2 +// a1 + a2 = 1 +// +// The vector from the origin to the closest point on the line is +// perpendicular to the line. +// e12 = w2 - w1 +// dot(p, e) = 0 +// a1 * dot(w1, e) + a2 * dot(w2, e) = 0 +// +// 2-by-2 linear system +// [1 1 ][a1] = [1] +// [w1.e12 w2.e12][a2] = [0] +// +// Define +// d12_1 = dot(w2, e12) +// d12_2 = -dot(w1, e12) +// d12 = d12_1 + d12_2 +// +// Solution +// a1 = d12_1 / d12 +// a2 = d12_2 / d12 +void b2Simplex::Solve2() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 e12 = w2 - w1; + + // w1 region + float32 d12_2 = -b2Dot(w1, e12); + if (d12_2 <= 0.0f) + { + // a2 <= 0, so we clamp it to 0 + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // w2 region + float32 d12_1 = b2Dot(w2, e12); + if (d12_1 <= 0.0f) + { + // a1 <= 0, so we clamp it to 0 + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // Must be in e12 region. + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; +} + +// Possible regions: +// - points[2] +// - edge points[0]-points[2] +// - edge points[1]-points[2] +// - inside the triangle +void b2Simplex::Solve3() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 w3 = m_v3.w; + + // Edge12 + // [1 1 ][a1] = [1] + // [w1.e12 w2.e12][a2] = [0] + // a3 = 0 + b2Vec2 e12 = w2 - w1; + float32 w1e12 = b2Dot(w1, e12); + float32 w2e12 = b2Dot(w2, e12); + float32 d12_1 = w2e12; + float32 d12_2 = -w1e12; + + // Edge13 + // [1 1 ][a1] = [1] + // [w1.e13 w3.e13][a3] = [0] + // a2 = 0 + b2Vec2 e13 = w3 - w1; + float32 w1e13 = b2Dot(w1, e13); + float32 w3e13 = b2Dot(w3, e13); + float32 d13_1 = w3e13; + float32 d13_2 = -w1e13; + + // Edge23 + // [1 1 ][a2] = [1] + // [w2.e23 w3.e23][a3] = [0] + // a1 = 0 + b2Vec2 e23 = w3 - w2; + float32 w2e23 = b2Dot(w2, e23); + float32 w3e23 = b2Dot(w3, e23); + float32 d23_1 = w3e23; + float32 d23_2 = -w2e23; + + // Triangle123 + float32 n123 = b2Cross(e12, e13); + + float32 d123_1 = n123 * b2Cross(w2, w3); + float32 d123_2 = n123 * b2Cross(w3, w1); + float32 d123_3 = n123 * b2Cross(w1, w2); + + // w1 region + if (d12_2 <= 0.0f && d13_2 <= 0.0f) + { + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // e12 + if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) + { + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; + return; + } + + // e13 + if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) + { + float32 inv_d13 = 1.0f / (d13_1 + d13_2); + m_v1.a = d13_1 * inv_d13; + m_v3.a = d13_2 * inv_d13; + m_count = 2; + m_v2 = m_v3; + return; + } + + // w2 region + if (d12_1 <= 0.0f && d23_2 <= 0.0f) + { + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // w3 region + if (d13_1 <= 0.0f && d23_1 <= 0.0f) + { + m_v3.a = 1.0f; + m_count = 1; + m_v1 = m_v3; + return; + } + + // e23 + if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) + { + float32 inv_d23 = 1.0f / (d23_1 + d23_2); + m_v2.a = d23_1 * inv_d23; + m_v3.a = d23_2 * inv_d23; + m_count = 2; + m_v1 = m_v3; + return; + } + + // Must be in triangle123 + float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); + m_v1.a = d123_1 * inv_d123; + m_v2.a = d123_2 * inv_d123; + m_v3.a = d123_3 * inv_d123; + m_count = 3; +} + +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input) +{ + ++b2_gjkCalls; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Transform transformA = input->transformA; + b2Transform transformB = input->transformB; + + // Initialize the simplex. + b2Simplex simplex; + simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); + + // Get simplex vertices as an array. + b2SimplexVertex* vertices = &simplex.m_v1; + const int32 k_maxIters = 20; + + // These store the vertices of the last simplex so that we + // can check for duplicates and prevent cycling. + int32 saveA[3], saveB[3]; + int32 saveCount = 0; + + b2Vec2 closestPoint = simplex.GetClosestPoint(); + float32 distanceSqr1 = closestPoint.LengthSquared(); + float32 distanceSqr2 = distanceSqr1; + + // Main iteration loop. + int32 iter = 0; + while (iter < k_maxIters) + { + // Copy simplex so we can identify duplicates. + saveCount = simplex.m_count; + for (int32 i = 0; i < saveCount; ++i) + { + saveA[i] = vertices[i].indexA; + saveB[i] = vertices[i].indexB; + } + + switch (simplex.m_count) + { + case 1: + break; + + case 2: + simplex.Solve2(); + break; + + case 3: + simplex.Solve3(); + break; + + default: + b2Assert(false); + } + + // If we have 3 points, then the origin is in the corresponding triangle. + if (simplex.m_count == 3) + { + break; + } + + // Compute closest point. + b2Vec2 p = simplex.GetClosestPoint(); + distanceSqr2 = p.LengthSquared(); + + // Ensure progress + if (distanceSqr2 >= distanceSqr1) + { + //break; + } + distanceSqr1 = distanceSqr2; + + // Get search direction. + b2Vec2 d = simplex.GetSearchDirection(); + + // Ensure the search direction is numerically fit. + if (d.LengthSquared() < b2_epsilon * b2_epsilon) + { + // The origin is probably contained by a line segment + // or triangle. Thus the shapes are overlapped. + + // We can't return zero here even though there may be overlap. + // In case the simplex is a point, segment, or triangle it is difficult + // to determine if the origin is contained in the CSO or very close to it. + break; + } + + // Compute a tentative new simplex vertex using support points. + b2SimplexVertex* vertex = vertices + simplex.m_count; + vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); + vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); + b2Vec2 wBLocal; + vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); + vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); + vertex->w = vertex->wB - vertex->wA; + + // Iteration count is equated to the number of support point calls. + ++iter; + ++b2_gjkIters; + + // Check for duplicate support points. This is the main termination criteria. + bool duplicate = false; + for (int32 i = 0; i < saveCount; ++i) + { + if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) + { + duplicate = true; + break; + } + } + + // If we found a duplicate support point we must exit to avoid cycling. + if (duplicate) + { + break; + } + + // New vertex is ok and needed. + ++simplex.m_count; + } + + b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); + + // Prepare output. + simplex.GetWitnessPoints(&output->pointA, &output->pointB); + output->distance = b2Distance(output->pointA, output->pointB); + output->iterations = iter; + + // Cache the simplex. + simplex.WriteCache(cache); + + // Apply radii if requested. + if (input->useRadii) + { + float32 rA = proxyA->m_radius; + float32 rB = proxyB->m_radius; + + if (output->distance > rA + rB && output->distance > b2_epsilon) + { + // Shapes are still no overlapped. + // Move the witness points to the outer surface. + output->distance -= rA + rB; + b2Vec2 normal = output->pointB - output->pointA; + normal.Normalize(); + output->pointA += rA * normal; + output->pointB -= rB * normal; + } + else + { + // Shapes are overlapped when radii are considered. + // Move the witness points to the middle. + b2Vec2 p = 0.5f * (output->pointA + output->pointB); + output->pointA = p; + output->pointB = p; + output->distance = 0.0f; + } + } +} diff --git a/external/box2d/Collision/b2Distance.h b/external/box2d/Collision/b2Distance.h new file mode 100644 index 0000000000..d598b7339d --- /dev/null +++ b/external/box2d/Collision/b2Distance.h @@ -0,0 +1,141 @@ + +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_DISTANCE_H +#define B2_DISTANCE_H + +#include + +class b2Shape; + +/// A distance proxy is used by the GJK algorithm. +/// It encapsulates any shape. +struct b2DistanceProxy +{ + b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} + + /// Initialize the proxy using the given shape. The shape + /// must remain in scope while the proxy is in use. + void Set(const b2Shape* shape, int32 index); + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const; + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_buffer[2]; + const b2Vec2* m_vertices; + int32 m_count; + float32 m_radius; +}; + +/// Used to warm start b2Distance. +/// Set count to zero on first call. +struct b2SimplexCache +{ + float32 metric; ///< length or area + uint16 count; + uint8 indexA[3]; ///< vertices on shape A + uint8 indexB[3]; ///< vertices on shape B +}; + +/// Input for b2Distance. +/// You have to option to use the shape radii +/// in the computation. Even +struct b2DistanceInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Transform transformA; + b2Transform transformB; + bool useRadii; +}; + +/// Output for b2Distance. +struct b2DistanceOutput +{ + b2Vec2 pointA; ///< closest point on shapeA + b2Vec2 pointB; ///< closest point on shapeB + float32 distance; + int32 iterations; ///< number of GJK iterations used +}; + +/// Compute the closest points between two shapes. Supports any combination of: +/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. +/// On the first call set b2SimplexCache.count to zero. +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input); + + +////////////////////////////////////////////////////////////////////////// + +inline int32 b2DistanceProxy::GetVertexCount() const +{ + return m_count; +} + +inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_count); + return m_vertices[index]; +} + +inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return bestIndex; +} + +inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return m_vertices[bestIndex]; +} + +#endif diff --git a/external/box2d/Collision/b2DynamicTree.cpp b/external/box2d/Collision/b2DynamicTree.cpp new file mode 100644 index 0000000000..d1d53297e2 --- /dev/null +++ b/external/box2d/Collision/b2DynamicTree.cpp @@ -0,0 +1,775 @@ +/* +* Copyright (c) 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 +#include +#ifndef SHP +#include +#else +#include +#endif +using namespace std; + + +b2DynamicTree::b2DynamicTree() +{ + m_root = b2_nullNode; + + m_nodeCapacity = 16; + m_nodeCount = 0; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); + + // Build a linked list for the free list. + for (int32 i = 0; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = 0; + + m_path = 0; + + m_insertionCount = 0; +} + +b2DynamicTree::~b2DynamicTree() +{ + // This frees the entire tree in one shot. + b2Free(m_nodes); +} + +// Allocate a node from the pool. Grow the pool if necessary. +int32 b2DynamicTree::AllocateNode() +{ + // Expand the node pool as needed. + if (m_freeList == b2_nullNode) + { + b2Assert(m_nodeCount == m_nodeCapacity); + + // The free list is empty. Rebuild a bigger pool. + b2TreeNode* oldNodes = m_nodes; + m_nodeCapacity *= 2; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); + b2Free(oldNodes); + + // Build a linked list for the free list. The parent + // pointer becomes the "next" pointer. + for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = m_nodeCount; + } + + // Peel a node off the free list. + int32 nodeId = m_freeList; + m_freeList = m_nodes[nodeId].next; + m_nodes[nodeId].parent = b2_nullNode; + m_nodes[nodeId].child1 = b2_nullNode; + m_nodes[nodeId].child2 = b2_nullNode; + m_nodes[nodeId].height = 0; + m_nodes[nodeId].userData = NULL; + ++m_nodeCount; + return nodeId; +} + +// Return a node to the pool. +void b2DynamicTree::FreeNode(int32 nodeId) +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2Assert(0 < m_nodeCount); + m_nodes[nodeId].next = m_freeList; + m_nodes[nodeId].height = -1; + m_freeList = nodeId; + --m_nodeCount; +} + +// Create a proxy in the tree as a leaf node. We return the index +// of the node instead of a pointer so that we can grow +// the node pool. +int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = AllocateNode(); + + // Fatten the aabb. + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; + m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; + m_nodes[proxyId].userData = userData; + m_nodes[proxyId].height = 0; + + InsertLeaf(proxyId); + + return proxyId; +} + +void b2DynamicTree::DestroyProxy(int32 proxyId) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + b2Assert(m_nodes[proxyId].IsLeaf()); + + RemoveLeaf(proxyId); + FreeNode(proxyId); +} + +bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + + b2Assert(m_nodes[proxyId].IsLeaf()); + + if (m_nodes[proxyId].aabb.Contains(aabb)) + { + return false; + } + + RemoveLeaf(proxyId); + + // Extend AABB. + b2AABB b = aabb; + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + b.lowerBound = b.lowerBound - r; + b.upperBound = b.upperBound + r; + + // Predict AABB displacement. + b2Vec2 d = b2_aabbMultiplier * displacement; + + if (d.x < 0.0f) + { + b.lowerBound.x += d.x; + } + else + { + b.upperBound.x += d.x; + } + + if (d.y < 0.0f) + { + b.lowerBound.y += d.y; + } + else + { + b.upperBound.y += d.y; + } + + m_nodes[proxyId].aabb = b; + + InsertLeaf(proxyId); + return true; +} + +void b2DynamicTree::InsertLeaf(int32 leaf) +{ + ++m_insertionCount; + + if (m_root == b2_nullNode) + { + m_root = leaf; + m_nodes[m_root].parent = b2_nullNode; + return; + } + + // Find the best sibling for this node + b2AABB leafAABB = m_nodes[leaf].aabb; + int32 index = m_root; + while (m_nodes[index].IsLeaf() == false) + { + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + float32 area = m_nodes[index].aabb.GetPerimeter(); + + b2AABB combinedAABB; + combinedAABB.Combine(m_nodes[index].aabb, leafAABB); + float32 combinedArea = combinedAABB.GetPerimeter(); + + // Cost of creating a new parent for this node and the new leaf + float32 cost = 2.0f * combinedArea; + + // Minimum cost of pushing the leaf further down the tree + float32 inheritanceCost = 2.0f * (combinedArea - area); + + // Cost of descending into child1 + float32 cost1; + if (m_nodes[child1].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + cost1 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost1 = (newArea - oldArea) + inheritanceCost; + } + + // Cost of descending into child2 + float32 cost2; + if (m_nodes[child2].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + cost2 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost2 = newArea - oldArea + inheritanceCost; + } + + // Descend according to the minimum cost. + if (cost < cost1 && cost < cost2) + { + break; + } + + // Descend + if (cost1 < cost2) + { + index = child1; + } + else + { + index = child2; + } + } + + int32 sibling = index; + + // Create a new parent. + int32 oldParent = m_nodes[sibling].parent; + int32 newParent = AllocateNode(); + m_nodes[newParent].parent = oldParent; + m_nodes[newParent].userData = NULL; + m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); + m_nodes[newParent].height = m_nodes[sibling].height + 1; + + if (oldParent != b2_nullNode) + { + // The sibling was not the root. + if (m_nodes[oldParent].child1 == sibling) + { + m_nodes[oldParent].child1 = newParent; + } + else + { + m_nodes[oldParent].child2 = newParent; + } + + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + } + else + { + // The sibling was the root. + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + m_root = newParent; + } + + // Walk back up the tree fixing heights and AABBs + index = m_nodes[leaf].parent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + b2Assert(child1 != b2_nullNode); + b2Assert(child2 != b2_nullNode); + + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + index = m_nodes[index].parent; + } + + //Validate(); +} + +void b2DynamicTree::RemoveLeaf(int32 leaf) +{ + if (leaf == m_root) + { + m_root = b2_nullNode; + return; + } + + int32 parent = m_nodes[leaf].parent; + int32 grandParent = m_nodes[parent].parent; + int32 sibling; + if (m_nodes[parent].child1 == leaf) + { + sibling = m_nodes[parent].child2; + } + else + { + sibling = m_nodes[parent].child1; + } + + if (grandParent != b2_nullNode) + { + // Destroy parent and connect sibling to grandParent. + if (m_nodes[grandParent].child1 == parent) + { + m_nodes[grandParent].child1 = sibling; + } + else + { + m_nodes[grandParent].child2 = sibling; + } + m_nodes[sibling].parent = grandParent; + FreeNode(parent); + + // Adjust ancestor bounds. + int32 index = grandParent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + + index = m_nodes[index].parent; + } + } + else + { + m_root = sibling; + m_nodes[sibling].parent = b2_nullNode; + FreeNode(parent); + } + + //Validate(); +} + +// Perform a left or right rotation if node A is imbalanced. +// Returns the new root index. +int32 b2DynamicTree::Balance(int32 iA) +{ + b2Assert(iA != b2_nullNode); + + b2TreeNode* A = m_nodes + iA; + if (A->IsLeaf() || A->height < 2) + { + return iA; + } + + int32 iB = A->child1; + int32 iC = A->child2; + b2Assert(0 <= iB && iB < m_nodeCapacity); + b2Assert(0 <= iC && iC < m_nodeCapacity); + + b2TreeNode* B = m_nodes + iB; + b2TreeNode* C = m_nodes + iC; + + int32 balance = C->height - B->height; + + // Rotate C up + if (balance > 1) + { + int32 iF = C->child1; + int32 iG = C->child2; + b2TreeNode* F = m_nodes + iF; + b2TreeNode* G = m_nodes + iG; + b2Assert(0 <= iF && iF < m_nodeCapacity); + b2Assert(0 <= iG && iG < m_nodeCapacity); + + // Swap A and C + C->child1 = iA; + C->parent = A->parent; + A->parent = iC; + + // A's old parent should point to C + if (C->parent != b2_nullNode) + { + if (m_nodes[C->parent].child1 == iA) + { + m_nodes[C->parent].child1 = iC; + } + else + { + b2Assert(m_nodes[C->parent].child2 == iA); + m_nodes[C->parent].child2 = iC; + } + } + else + { + m_root = iC; + } + + // Rotate + if (F->height > G->height) + { + C->child2 = iF; + A->child2 = iG; + G->parent = iA; + A->aabb.Combine(B->aabb, G->aabb); + C->aabb.Combine(A->aabb, F->aabb); + + A->height = 1 + b2Max(B->height, G->height); + C->height = 1 + b2Max(A->height, F->height); + } + else + { + C->child2 = iG; + A->child2 = iF; + F->parent = iA; + A->aabb.Combine(B->aabb, F->aabb); + C->aabb.Combine(A->aabb, G->aabb); + + A->height = 1 + b2Max(B->height, F->height); + C->height = 1 + b2Max(A->height, G->height); + } + + return iC; + } + + // Rotate B up + if (balance < -1) + { + int32 iD = B->child1; + int32 iE = B->child2; + b2TreeNode* D = m_nodes + iD; + b2TreeNode* E = m_nodes + iE; + b2Assert(0 <= iD && iD < m_nodeCapacity); + b2Assert(0 <= iE && iE < m_nodeCapacity); + + // Swap A and B + B->child1 = iA; + B->parent = A->parent; + A->parent = iB; + + // A's old parent should point to B + if (B->parent != b2_nullNode) + { + if (m_nodes[B->parent].child1 == iA) + { + m_nodes[B->parent].child1 = iB; + } + else + { + b2Assert(m_nodes[B->parent].child2 == iA); + m_nodes[B->parent].child2 = iB; + } + } + else + { + m_root = iB; + } + + // Rotate + if (D->height > E->height) + { + B->child2 = iD; + A->child1 = iE; + E->parent = iA; + A->aabb.Combine(C->aabb, E->aabb); + B->aabb.Combine(A->aabb, D->aabb); + + A->height = 1 + b2Max(C->height, E->height); + B->height = 1 + b2Max(A->height, D->height); + } + else + { + B->child2 = iE; + A->child1 = iD; + D->parent = iA; + A->aabb.Combine(C->aabb, D->aabb); + B->aabb.Combine(A->aabb, E->aabb); + + A->height = 1 + b2Max(C->height, D->height); + B->height = 1 + b2Max(A->height, E->height); + } + + return iB; + } + + return iA; +} + +int32 b2DynamicTree::GetHeight() const +{ + if (m_root == b2_nullNode) + { + return 0; + } + + return m_nodes[m_root].height; +} + +// +float32 b2DynamicTree::GetAreaRatio() const +{ + if (m_root == b2_nullNode) + { + return 0.0f; + } + + const b2TreeNode* root = m_nodes + m_root; + float32 rootArea = root->aabb.GetPerimeter(); + + float32 totalArea = 0.0f; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height < 0) + { + // Free node in pool + continue; + } + + totalArea += node->aabb.GetPerimeter(); + } + + return totalArea / rootArea; +} + +// Compute the height of a sub-tree. +int32 b2DynamicTree::ComputeHeight(int32 nodeId) const +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2TreeNode* node = m_nodes + nodeId; + + if (node->IsLeaf()) + { + return 0; + } + + int32 height1 = ComputeHeight(node->child1); + int32 height2 = ComputeHeight(node->child2); + return 1 + b2Max(height1, height2); +} + +int32 b2DynamicTree::ComputeHeight() const +{ + int32 height = ComputeHeight(m_root); + return height; +} + +void b2DynamicTree::ValidateStructure(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + if (index == m_root) + { + b2Assert(m_nodes[index].parent == b2_nullNode); + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + b2Assert(m_nodes[child1].parent == index); + b2Assert(m_nodes[child2].parent == index); + + ValidateStructure(child1); + ValidateStructure(child2); +} + +void b2DynamicTree::ValidateMetrics(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + int32 height1 = m_nodes[child1].height; + int32 height2 = m_nodes[child2].height; + int32 height; + height = 1 + b2Max(height1, height2); + b2Assert(node->height == height); + + b2AABB aabb; + aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + b2Assert(aabb.lowerBound == node->aabb.lowerBound); + b2Assert(aabb.upperBound == node->aabb.upperBound); + + ValidateMetrics(child1); + ValidateMetrics(child2); +} + +void b2DynamicTree::Validate() const +{ + ValidateStructure(m_root); + ValidateMetrics(m_root); + + int32 freeCount = 0; + int32 freeIndex = m_freeList; + while (freeIndex != b2_nullNode) + { + b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); + freeIndex = m_nodes[freeIndex].next; + ++freeCount; + } + + b2Assert(GetHeight() == ComputeHeight()); + + b2Assert(m_nodeCount + freeCount == m_nodeCapacity); +} + +int32 b2DynamicTree::GetMaxBalance() const +{ + int32 maxBalance = 0; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height <= 1) + { + continue; + } + + b2Assert(node->IsLeaf() == false); + + int32 child1 = node->child1; + int32 child2 = node->child2; + int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); + maxBalance = b2Max(maxBalance, balance); + } + + return maxBalance; +} + +void b2DynamicTree::RebuildBottomUp() +{ + int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); + int32 count = 0; + + // Build array of leaves. Free the rest. + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + if (m_nodes[i].height < 0) + { + // free node in pool + continue; + } + + if (m_nodes[i].IsLeaf()) + { + m_nodes[i].parent = b2_nullNode; + nodes[count] = i; + ++count; + } + else + { + FreeNode(i); + } + } + + while (count > 1) + { + float32 minCost = b2_maxFloat; + int32 iMin = -1, jMin = -1; + for (int32 i = 0; i < count; ++i) + { + b2AABB aabbi = m_nodes[nodes[i]].aabb; + + for (int32 j = i + 1; j < count; ++j) + { + b2AABB aabbj = m_nodes[nodes[j]].aabb; + b2AABB b; + b.Combine(aabbi, aabbj); + float32 cost = b.GetPerimeter(); + if (cost < minCost) + { + iMin = i; + jMin = j; + minCost = cost; + } + } + } + + int32 index1 = nodes[iMin]; + int32 index2 = nodes[jMin]; + b2TreeNode* child1 = m_nodes + index1; + b2TreeNode* child2 = m_nodes + index2; + + int32 parentIndex = AllocateNode(); + b2TreeNode* parent = m_nodes + parentIndex; + parent->child1 = index1; + parent->child2 = index2; + parent->height = 1 + b2Max(child1->height, child2->height); + parent->aabb.Combine(child1->aabb, child2->aabb); + parent->parent = b2_nullNode; + + child1->parent = parentIndex; + child2->parent = parentIndex; + + nodes[jMin] = nodes[count-1]; + nodes[iMin] = parentIndex; + --count; + } + + m_root = nodes[0]; + b2Free(nodes); + + Validate(); +} diff --git a/external/box2d/Collision/b2DynamicTree.h b/external/box2d/Collision/b2DynamicTree.h new file mode 100644 index 0000000000..33f16b0f32 --- /dev/null +++ b/external/box2d/Collision/b2DynamicTree.h @@ -0,0 +1,284 @@ +/* +* Copyright (c) 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. +*/ + +#ifndef B2_DYNAMIC_TREE_H +#define B2_DYNAMIC_TREE_H + +#include +#include + +#define b2_nullNode (-1) + +/// A node in the dynamic tree. The client does not interact with this directly. +struct b2TreeNode +{ + bool IsLeaf() const + { + return child1 == b2_nullNode; + } + + /// Enlarged AABB + b2AABB aabb; + + void* userData; + + union + { + int32 parent; + int32 next; + }; + + int32 child1; + int32 child2; + + // leaf = 0, free node = -1 + int32 height; +}; + +/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. +/// A dynamic tree arranges data in a binary tree to accelerate +/// queries such as volume queries and ray casts. Leafs are proxies +/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor +/// so that the proxy AABB is bigger than the client object. This allows the client +/// object to move by small amounts without triggering a tree update. +/// +/// Nodes are pooled and relocatable, so we use node indices rather than pointers. +class b2DynamicTree +{ +public: + /// Constructing the tree initializes the node pool. + b2DynamicTree(); + + /// Destroy the tree, freeing the node pool. + ~b2DynamicTree(); + + /// Create a proxy. Provide a tight fitting AABB and a userData pointer. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. This asserts if the id is invalid. + void DestroyProxy(int32 proxyId); + + /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, + /// then the proxy is removed from the tree and re-inserted. Otherwise + /// the function returns immediately. + /// @return true if the proxy was re-inserted. + bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); + + /// Get proxy user data. + /// @return the proxy user data or 0 if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Validate this tree. For testing. + void Validate() const; + + /// Compute the height of the binary tree in O(N) time. Should not be + /// called often. + int32 GetHeight() const; + + /// Get the maximum balance of an node in the tree. The balance is the difference + /// in height of the two children of a node. + int32 GetMaxBalance() const; + + /// Get the ratio of the sum of the node areas to the root area. + float32 GetAreaRatio() const; + + /// Build an optimal tree. Very expensive. For testing. + void RebuildBottomUp(); + +private: + + int32 AllocateNode(); + void FreeNode(int32 node); + + void InsertLeaf(int32 node); + void RemoveLeaf(int32 node); + + int32 Balance(int32 index); + + int32 ComputeHeight() const; + int32 ComputeHeight(int32 nodeId) const; + + void ValidateStructure(int32 index) const; + void ValidateMetrics(int32 index) const; + + int32 m_root; + + b2TreeNode* m_nodes; + int32 m_nodeCount; + int32 m_nodeCapacity; + + int32 m_freeList; + + /// This is used to incrementally traverse the tree for re-balancing. + uint32 m_path; + + int32 m_insertionCount; +}; + +inline void* b2DynamicTree::GetUserData(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].userData; +} + +inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].aabb; +} + +template +inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const +{ + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, aabb)) + { + if (node->IsLeaf()) + { + bool proceed = callback->QueryCallback(nodeId); + if (proceed == false) + { + return; + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } + } +} + +template +inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const +{ + b2Vec2 p1 = input.p1; + b2Vec2 p2 = input.p2; + b2Vec2 r = p2 - p1; + b2Assert(r.LengthSquared() > 0.0f); + r.Normalize(); + + // v is perpendicular to the segment. + b2Vec2 v = b2Cross(1.0f, r); + b2Vec2 abs_v = b2Abs(v); + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + + float32 maxFraction = input.maxFraction; + + // Build a bounding box for the segment. + b2AABB segmentAABB; + { + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, segmentAABB) == false) + { + continue; + } + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + b2Vec2 c = node->aabb.GetCenter(); + b2Vec2 h = node->aabb.GetExtents(); + float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); + if (separation > 0.0f) + { + continue; + } + + if (node->IsLeaf()) + { + b2RayCastInput subInput; + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = maxFraction; + + float32 value = callback->RayCastCallback(subInput, nodeId); + + if (value == 0.0f) + { + // The client has terminated the ray cast. + return; + } + + if (value > 0.0f) + { + // Update segment bounding box. + maxFraction = value; + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } +} + +#endif diff --git a/external/box2d/Collision/b2TimeOfImpact.cpp b/external/box2d/Collision/b2TimeOfImpact.cpp new file mode 100644 index 0000000000..1d643addd8 --- /dev/null +++ b/external/box2d/Collision/b2TimeOfImpact.cpp @@ -0,0 +1,488 @@ +/* +* 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 +#include +#include +#include +#include + +#ifdef SHP +#include +#else +#include +#endif + +using namespace std; + +int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; +int32 b2_toiRootIters, b2_toiMaxRootIters; + +struct b2SeparationFunction +{ + enum Type + { + e_points, + e_faceA, + e_faceB + }; + + // TODO_ERIN might not need to return the separation + + float32 Initialize(const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Sweep& sweepA, + const b2DistanceProxy* proxyB, const b2Sweep& sweepB, + float32 t1) + { + m_proxyA = proxyA; + m_proxyB = proxyB; + int32 count = cache->count; + b2Assert(0 < count && count < 3); + + m_sweepA = sweepA; + m_sweepB = sweepB; + + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t1); + m_sweepB.GetTransform(&xfB, t1); + + if (count == 1) + { + m_type = e_points; + b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + m_axis = pointB - pointA; + float32 s = m_axis.Normalize(); + return s; + } + else if (cache->indexA[0] == cache->indexA[1]) + { + // Two points on B and one on A. + m_type = e_faceB; + b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); + b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); + + m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfB.q, m_axis); + + m_localPoint = 0.5f * (localPointB1 + localPointB2); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 s = b2Dot(pointA - pointB, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + else + { + // Two points on A and one or two points on B. + m_type = e_faceA; + b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); + + m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfA.q, m_axis); + + m_localPoint = 0.5f * (localPointA1 + localPointA2); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 s = b2Dot(pointB - pointA, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + } + + float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + *indexA = m_proxyA->GetSupport(axisA); + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, m_axis); + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + *indexA = -1; + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + *indexB = -1; + *indexA = m_proxyA->GetSupport(axisA); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + *indexA = -1; + *indexB = -1; + return 0.0f; + } + } + + float32 Evaluate(int32 indexA, int32 indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + float32 separation = b2Dot(pointB - pointA, m_axis); + + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + return 0.0f; + } + } + + const b2DistanceProxy* m_proxyA; + const b2DistanceProxy* m_proxyB; + b2Sweep m_sweepA, m_sweepB; + Type m_type; + b2Vec2 m_localPoint; + b2Vec2 m_axis; +}; + +// CCD via the local separating axis method. This seeks progression +// by computing the largest time at which separation is maintained. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) +{ + ++b2_toiCalls; + + output->state = b2TOIOutput::e_unknown; + output->t = input->tMax; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Sweep sweepA = input->sweepA; + b2Sweep sweepB = input->sweepB; + + // Large rotations can make the root finder fail, so we normalize the + // sweep angles. + sweepA.Normalize(); + sweepB.Normalize(); + + float32 tMax = input->tMax; + + float32 totalRadius = proxyA->m_radius + proxyB->m_radius; + float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); + float32 tolerance = 0.25f * b2_linearSlop; + b2Assert(target > tolerance); + + float32 t1 = 0.0f; + const int32 k_maxIterations = 20; // TODO_ERIN b2Settings + int32 iter = 0; + + // Prepare input for distance query. + b2SimplexCache cache; + cache.count = 0; + b2DistanceInput distanceInput; + distanceInput.proxyA = input->proxyA; + distanceInput.proxyB = input->proxyB; + distanceInput.useRadii = false; + + // The outer loop progressively attempts to compute new separating axes. + // This loop terminates when an axis is repeated (no progress is made). + for(;;) + { + b2Transform xfA, xfB; + sweepA.GetTransform(&xfA, t1); + sweepB.GetTransform(&xfB, t1); + + // Get the distance between shapes. We can also use the results + // to get a separating axis. + distanceInput.transformA = xfA; + distanceInput.transformB = xfB; + b2DistanceOutput distanceOutput; + b2Distance(&distanceOutput, &cache, &distanceInput); + + // If the shapes are overlapped, we give up on continuous collision. + if (distanceOutput.distance <= 0.0f) + { + // Failure! + output->state = b2TOIOutput::e_overlapped; + output->t = 0.0f; + break; + } + + if (distanceOutput.distance < target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_touching; + output->t = t1; + break; + } + + // Initialize the separating axis. + b2SeparationFunction fcn; + fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); +#if 0 + // Dump the curve seen by the root finder + { + const int32 N = 100; + float32 dx = 1.0f / N; + float32 xs[N+1]; + float32 fs[N+1]; + + float32 x = 0.0f; + + for (int32 i = 0; i <= N; ++i) + { + sweepA.GetTransform(&xfA, x); + sweepB.GetTransform(&xfB, x); + float32 f = fcn.Evaluate(xfA, xfB) - target; + + printf("%g %g\n", x, f); + + xs[i] = x; + fs[i] = f; + + x += dx; + } + } +#endif + + // Compute the TOI on the separating axis. We do this by successively + // resolving the deepest point. This loop is bounded by the number of vertices. + bool done = false; + float32 t2 = tMax; + int32 pushBackIter = 0; + for (;;) + { + // Find the deepest point at t2. Store the witness point indices. + int32 indexA, indexB; + float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); + + // Is the final configuration separated? + if (s2 > target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_separated; + output->t = tMax; + done = true; + break; + } + + // Has the separation reached tolerance? + if (s2 > target - tolerance) + { + // Advance the sweeps + t1 = t2; + break; + } + + // Compute the initial separation of the witness points. + float32 s1 = fcn.Evaluate(indexA, indexB, t1); + + // Check for initial overlap. This might happen if the root finder + // runs out of iterations. + if (s1 < target - tolerance) + { + output->state = b2TOIOutput::e_failed; + output->t = t1; + done = true; + break; + } + + // Check for touching + if (s1 <= target + tolerance) + { + // Victory! t1 should hold the TOI (could be 0.0). + output->state = b2TOIOutput::e_touching; + output->t = t1; + done = true; + break; + } + + // Compute 1D root of: f(x) - target = 0 + int32 rootIterCount = 0; + float32 a1 = t1, a2 = t2; + for (;;) + { + // Use a mix of the secant rule and bisection. + float32 t; + if (rootIterCount & 1) + { + // Secant rule to improve convergence. + t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); + } + else + { + // Bisection to guarantee progress. + t = 0.5f * (a1 + a2); + } + + float32 s = fcn.Evaluate(indexA, indexB, t); + + if (b2Abs(s - target) < tolerance) + { + // t2 holds a tentative value for t1 + t2 = t; + break; + } + + // Ensure we continue to bracket the root. + if (s > target) + { + a1 = t; + s1 = s; + } + else + { + a2 = t; + s2 = s; + } + + ++rootIterCount; + ++b2_toiRootIters; + + if (rootIterCount == 50) + { + break; + } + } + + b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); + + ++pushBackIter; + + if (pushBackIter == b2_maxPolygonVertices) + { + break; + } + } + + ++iter; + ++b2_toiIters; + + if (done) + { + break; + } + + if (iter == k_maxIterations) + { + // Root finder got stuck. Semi-victory. + output->state = b2TOIOutput::e_failed; + output->t = t1; + break; + } + } + + b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); +} diff --git a/external/box2d/Collision/b2TimeOfImpact.h b/external/box2d/Collision/b2TimeOfImpact.h new file mode 100644 index 0000000000..2e4f8228ff --- /dev/null +++ b/external/box2d/Collision/b2TimeOfImpact.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_TIME_OF_IMPACT_H +#define B2_TIME_OF_IMPACT_H + +#include +#include + +/// Input parameters for b2TimeOfImpact +struct b2TOIInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Sweep sweepA; + b2Sweep sweepB; + float32 tMax; // defines sweep interval [0, tMax] +}; + +// Output parameters for b2TimeOfImpact. +struct b2TOIOutput +{ + enum State + { + e_unknown, + e_failed, + e_overlapped, + e_touching, + e_separated + }; + + State state; + float32 t; +}; + +/// Compute the upper bound on time before two shapes penetrate. Time is represented as +/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, +/// non-tunneling collision. If you change the time interval, you should call this function +/// again. +/// Note: use b2Distance to compute the contact point and normal at the time of impact. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); + +#endif diff --git a/external/box2d/Common/b2BlockAllocator.cpp b/external/box2d/Common/b2BlockAllocator.cpp new file mode 100644 index 0000000000..2e862091f9 --- /dev/null +++ b/external/box2d/Common/b2BlockAllocator.cpp @@ -0,0 +1,218 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include + +using namespace std; + +int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = +{ + 16, // 0 + 32, // 1 + 64, // 2 + 96, // 3 + 128, // 4 + 160, // 5 + 192, // 6 + 224, // 7 + 256, // 8 + 320, // 9 + 384, // 10 + 448, // 11 + 512, // 12 + 640, // 13 +}; +uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; +bool b2BlockAllocator::s_blockSizeLookupInitialized; + +struct b2Chunk +{ + int32 blockSize; + b2Block* blocks; +}; + +struct b2Block +{ + b2Block* next; +}; + +b2BlockAllocator::b2BlockAllocator() +{ + b2Assert(b2_blockSizes < UCHAR_MAX); + + m_chunkSpace = b2_chunkArrayIncrement; + m_chunkCount = 0; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + memset(m_freeLists, 0, sizeof(m_freeLists)); + + if (s_blockSizeLookupInitialized == false) + { + int32 j = 0; + for (int32 i = 1; i <= b2_maxBlockSize; ++i) + { + b2Assert(j < b2_blockSizes); + if (i <= s_blockSizes[j]) + { + s_blockSizeLookup[i] = (uint8)j; + } + else + { + ++j; + s_blockSizeLookup[i] = (uint8)j; + } + } + + s_blockSizeLookupInitialized = true; + } +} + +b2BlockAllocator::~b2BlockAllocator() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + b2Free(m_chunks); +} + +void* b2BlockAllocator::Allocate(int32 size) +{ + if (size == 0) + return NULL; + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + return b2Alloc(size); + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + + if (m_freeLists[index]) + { + b2Block* block = m_freeLists[index]; + m_freeLists[index] = block->next; + return block; + } + else + { + if (m_chunkCount == m_chunkSpace) + { + b2Chunk* oldChunks = m_chunks; + m_chunkSpace += b2_chunkArrayIncrement; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); + memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); + b2Free(oldChunks); + } + + b2Chunk* chunk = m_chunks + m_chunkCount; + chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); +#if defined(_DEBUG) + memset(chunk->blocks, 0xcd, b2_chunkSize); +#endif + int32 blockSize = s_blockSizes[index]; + chunk->blockSize = blockSize; + int32 blockCount = b2_chunkSize / blockSize; + b2Assert(blockCount * blockSize <= b2_chunkSize); + for (int32 i = 0; i < blockCount - 1; ++i) + { + b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); + b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); + block->next = next; + } + b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); + last->next = NULL; + + m_freeLists[index] = chunk->blocks->next; + ++m_chunkCount; + + return chunk->blocks; + } +} + +void b2BlockAllocator::Free(void* p, int32 size) +{ + if (size == 0) + { + return; + } + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + b2Free(p); + return; + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + +#ifdef _DEBUG + // Verify the memory address and size is valid. + int32 blockSize = s_blockSizes[index]; + bool found = false; + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Chunk* chunk = m_chunks + i; + if (chunk->blockSize != blockSize) + { + b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || + (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); + } + else + { + if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) + { + found = true; + } + } + } + + b2Assert(found); + + memset(p, 0xfd, blockSize); +#endif + + b2Block* block = (b2Block*)p; + block->next = m_freeLists[index]; + m_freeLists[index] = block; +} + +void b2BlockAllocator::Clear() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + m_chunkCount = 0; + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + + memset(m_freeLists, 0, sizeof(m_freeLists)); +} diff --git a/external/box2d/Common/b2BlockAllocator.h b/external/box2d/Common/b2BlockAllocator.h new file mode 100644 index 0000000000..ec221fdf61 --- /dev/null +++ b/external/box2d/Common/b2BlockAllocator.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_BLOCK_ALLOCATOR_H +#define B2_BLOCK_ALLOCATOR_H + +#include + +const int32 b2_chunkSize = 16 * 1024; +const int32 b2_maxBlockSize = 640; +const int32 b2_blockSizes = 14; +const int32 b2_chunkArrayIncrement = 128; + +struct b2Block; +struct b2Chunk; + +/// This is a small object allocator used for allocating small +/// objects that persist for more than one time step. +/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp +class b2BlockAllocator +{ +public: + b2BlockAllocator(); + ~b2BlockAllocator(); + + /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. + void* Allocate(int32 size); + + /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. + void Free(void* p, int32 size); + + void Clear(); + +private: + + b2Chunk* m_chunks; + int32 m_chunkCount; + int32 m_chunkSpace; + + b2Block* m_freeLists[b2_blockSizes]; + + static int32 s_blockSizes[b2_blockSizes]; + static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; + static bool s_blockSizeLookupInitialized; +}; + +#endif diff --git a/external/box2d/Common/b2Draw.cpp b/external/box2d/Common/b2Draw.cpp new file mode 100644 index 0000000000..cb760025e9 --- /dev/null +++ b/external/box2d/Common/b2Draw.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +b2Draw::b2Draw() +{ + m_drawFlags = 0; +} + +void b2Draw::SetFlags(uint32 flags) +{ + m_drawFlags = flags; +} + +uint32 b2Draw::GetFlags() const +{ + return m_drawFlags; +} + +void b2Draw::AppendFlags(uint32 flags) +{ + m_drawFlags |= flags; +} + +void b2Draw::ClearFlags(uint32 flags) +{ + m_drawFlags &= ~flags; +} diff --git a/external/box2d/Common/b2Draw.h b/external/box2d/Common/b2Draw.h new file mode 100644 index 0000000000..b33cd8d38f --- /dev/null +++ b/external/box2d/Common/b2Draw.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +/// Color for debug drawing. Each value has the range [0,1]. +struct b2Color +{ + b2Color() {} + b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} + void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } + float32 r, g, b; +}; + +/// Implement and register this class with a b2World to provide debug drawing of physics +/// entities in your game. +class b2Draw +{ +public: + b2Draw(); + + virtual ~b2Draw() {} + + enum + { + e_shapeBit = 0x0001, ///< draw shapes + e_jointBit = 0x0002, ///< draw joint connections + e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes + e_pairBit = 0x0008, ///< draw broad-phase pairs + e_centerOfMassBit = 0x0010 ///< draw center of mass frame + }; + + /// Set the drawing flags. + void SetFlags(uint32 flags); + + /// Get the drawing flags. + uint32 GetFlags() const; + + /// Append flags to the current flags. + void AppendFlags(uint32 flags); + + /// Clear flags from the current flags. + void ClearFlags(uint32 flags); + + /// Draw a closed polygon provided in CCW order. + virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a solid closed polygon provided in CCW order. + virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a circle. + virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; + + /// Draw a solid circle. + virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; + + /// Draw a line segment. + virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; + + /// Draw a transform. Choose your own length scale. + /// @param xf a transform. + virtual void DrawTransform(const b2Transform& xf) = 0; + +protected: + uint32 m_drawFlags; +}; diff --git a/external/box2d/Common/b2GrowableStack.h b/external/box2d/Common/b2GrowableStack.h new file mode 100644 index 0000000000..68809521f4 --- /dev/null +++ b/external/box2d/Common/b2GrowableStack.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2010 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. +*/ + +#ifndef B2_GROWABLE_STACK_H +#define B2_GROWABLE_STACK_H +#include +#include + +/// This is a growable LIFO stack with an initial capacity of N. +/// If the stack size exceeds the initial capacity, the heap is used +/// to increase the size of the stack. +template +class b2GrowableStack +{ +public: + b2GrowableStack() + { + m_stack = m_array; + m_count = 0; + m_capacity = N; + } + + ~b2GrowableStack() + { + if (m_stack != m_array) + { + b2Free(m_stack); + m_stack = NULL; + } + } + + void Push(const T& element) + { + if (m_count == m_capacity) + { + T* old = m_stack; + m_capacity *= 2; + m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); + std::memcpy(m_stack, old, m_count * sizeof(T)); + if (old != m_array) + { + b2Free(old); + } + } + + m_stack[m_count] = element; + ++m_count; + } + + T Pop() + { + b2Assert(m_count > 0); + --m_count; + return m_stack[m_count]; + } + + int32 GetCount() + { + return m_count; + } + +private: + T* m_stack; + T m_array[N]; + int32 m_count; + int32 m_capacity; +}; + + +#endif diff --git a/external/box2d/Common/b2Math.cpp b/external/box2d/Common/b2Math.cpp new file mode 100644 index 0000000000..15d68fce96 --- /dev/null +++ b/external/box2d/Common/b2Math.cpp @@ -0,0 +1,94 @@ +/* +* 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 + +const b2Vec2 b2Vec2_zero(0.0f, 0.0f); + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec3 x; + x.x = det * b2Dot(b, b2Cross(ey, ez)); + x.y = det * b2Dot(ex, b2Cross(b, ez)); + x.z = det * b2Dot(ex, b2Cross(ey, b)); + return x; +} + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const +{ + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; +} + +/// +void b2Mat33::GetInverse22(b2Mat33* M) const +{ + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + + M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; + M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; + M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; +} + +/// Returns the zero matrix if singular. +void b2Mat33::GetSymInverse33(b2Mat33* M) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + + float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; + float32 a22 = ey.y, a23 = ez.y; + float32 a33 = ez.z; + + M->ex.x = det * (a22 * a33 - a23 * a23); + M->ex.y = det * (a13 * a23 - a12 * a33); + M->ex.z = det * (a12 * a23 - a13 * a22); + + M->ey.x = M->ex.y; + M->ey.y = det * (a11 * a33 - a13 * a13); + M->ey.z = det * (a13 * a12 - a11 * a23); + + M->ez.x = M->ex.z; + M->ez.y = M->ey.z; + M->ez.z = det * (a11 * a22 - a12 * a12); +} diff --git a/external/box2d/Common/b2Math.h b/external/box2d/Common/b2Math.h new file mode 100644 index 0000000000..a6be671139 --- /dev/null +++ b/external/box2d/Common/b2Math.h @@ -0,0 +1,738 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_MATH_H +#define B2_MATH_H + +#include + +#include +#ifndef SHP +#include +#else +#include +#endif +#include +#include + +using namespace std; + + +/// This function is used to ensure that a floating point number is +/// not a NaN or infinity. +inline bool b2IsValid(float32 x) +{ + if (x != x) + { + // NaN. + return false; + } + + float32 infinity = std::numeric_limits::infinity(); + return -infinity < x && x < infinity; +} + +/// This is a approximate yet fast inverse square-root. +inline float32 b2InvSqrt(float32 x) +{ + union + { + float32 x; + int32 i; + } convert; + + convert.x = x; + float32 xhalf = 0.5f * x; + convert.i = 0x5f3759df - (convert.i >> 1); + x = convert.x; + x = x * (1.5f - xhalf * x * x); + return x; +} + +#define b2Sqrt(x) std::sqrt(x) +#define b2Atan2(y, x) std::atan2(y, x) + +/// A 2D column vector. +struct b2Vec2 +{ + /// Default constructor does nothing (for performance). + b2Vec2() {} + + /// Construct using coordinates. + b2Vec2(float32 x, float32 y) : x(x), y(y) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_) { x = x_; y = y_; } + + /// Negate this vector. + b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } + + /// Read from and indexed element. + float32 operator () (int32 i) const + { + return (&x)[i]; + } + + /// Write to an indexed element. + float32& operator () (int32 i) + { + return (&x)[i]; + } + + /// Add a vector to this vector. + void operator += (const b2Vec2& v) + { + x += v.x; y += v.y; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec2& v) + { + x -= v.x; y -= v.y; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 a) + { + x *= a; y *= a; + } + + /// Get the length of this vector (the norm). + float32 Length() const + { + return b2Sqrt(x * x + y * y); + } + + /// Get the length squared. For performance, use this instead of + /// b2Vec2::Length (if possible). + float32 LengthSquared() const + { + return x * x + y * y; + } + + /// Convert this vector into a unit vector. Returns the length. + float32 Normalize() + { + float32 length = Length(); + if (length < b2_epsilon) + { + return 0.0f; + } + float32 invLength = 1.0f / length; + x *= invLength; + y *= invLength; + + return length; + } + + /// Does this vector contain finite coordinates? + bool IsValid() const + { + return b2IsValid(x) && b2IsValid(y); + } + + /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) + b2Vec2 Skew() const + { + return b2Vec2(-y, x); + } + + float32 x, y; +}; + +/// A 2D column vector with 3 elements. +struct b2Vec3 +{ + /// Default constructor does nothing (for performance). + b2Vec3() {} + + /// Construct using coordinates. + b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } + + /// Negate this vector. + b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } + + /// Add a vector to this vector. + void operator += (const b2Vec3& v) + { + x += v.x; y += v.y; z += v.z; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec3& v) + { + x -= v.x; y -= v.y; z -= v.z; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 s) + { + x *= s; y *= s; z *= s; + } + + float32 x, y, z; +}; + +/// A 2-by-2 matrix. Stored in column-major order. +struct b2Mat22 +{ + /// The default constructor does nothing (for performance). + b2Mat22() {} + + /// Construct this matrix using columns. + b2Mat22(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Construct this matrix using scalars. + b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) + { + ex.x = a11; ex.y = a21; + ey.x = a12; ey.y = a22; + } + + /// Initialize this matrix using columns. + void Set(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Set this to the identity matrix. + void SetIdentity() + { + ex.x = 1.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 1.0f; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.x = 0.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 0.0f; + } + + b2Mat22 GetInverse() const + { + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + b2Mat22 B; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + B.ex.x = det * d; B.ey.x = -det * b; + B.ex.y = -det * c; B.ey.y = det * a; + return B; + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec2 Solve(const b2Vec2& b) const + { + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; + } + + b2Vec2 ex, ey; +}; + +/// A 3-by-3 matrix. Stored in column-major order. +struct b2Mat33 +{ + /// The default constructor does nothing (for performance). + b2Mat33() {} + + /// Construct this matrix using columns. + b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) + { + ex = c1; + ey = c2; + ez = c3; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.SetZero(); + ey.SetZero(); + ez.SetZero(); + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec3 Solve33(const b2Vec3& b) const; + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. Solve only the upper + /// 2-by-2 matrix equation. + b2Vec2 Solve22(const b2Vec2& b) const; + + /// Get the inverse of this matrix as a 2-by-2. + /// Returns the zero matrix if singular. + void GetInverse22(b2Mat33* M) const; + + /// Get the symmetric inverse of this matrix as a 3-by-3. + /// Returns the zero matrix if singular. + void GetSymInverse33(b2Mat33* M) const; + + b2Vec3 ex, ey, ez; +}; + +/// Rotation +struct b2Rot +{ + b2Rot() {} + + /// Initialize from an angle in radians + explicit b2Rot(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set using an angle in radians. + void Set(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set to the identity rotation + void SetIdentity() + { + s = 0.0f; + c = 1.0f; + } + + /// Get the angle in radians + float32 GetAngle() const + { + return b2Atan2(s, c); + } + + /// Get the x-axis + b2Vec2 GetXAxis() const + { + return b2Vec2(c, s); + } + + /// Get the u-axis + b2Vec2 GetYAxis() const + { + return b2Vec2(-s, c); + } + + /// Sine and cosine + float32 s, c; +}; + +/// A transform contains translation and rotation. It is used to represent +/// the position and orientation of rigid frames. +struct b2Transform +{ + /// The default constructor does nothing. + b2Transform() {} + + /// Initialize using a position vector and a rotation. + b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} + + /// Set this to the identity transform. + void SetIdentity() + { + p.SetZero(); + q.SetIdentity(); + } + + /// Set this based on the position and angle. + void Set(const b2Vec2& position, float32 angle) + { + p = position; + q.Set(angle); + } + + b2Vec2 p; + b2Rot q; +}; + +/// This describes the motion of a body/shape for TOI computation. +/// Shapes are defined with respect to the body origin, which may +/// no coincide with the center of mass. However, to support dynamics +/// we must interpolate the center of mass position. +struct b2Sweep +{ + /// Get the interpolated transform at a specific time. + /// @param beta is a factor in [0,1], where 0 indicates alpha0. + void GetTransform(b2Transform* xfb, float32 beta) const; + + /// Advance the sweep forward, yielding a new initial state. + /// @param alpha the new initial time. + void Advance(float32 alpha); + + /// Normalize the angles. + void Normalize(); + + b2Vec2 localCenter; ///< local center of mass position + b2Vec2 c0, c; ///< center world positions + float32 a0, a; ///< world angles + + /// Fraction of the current time step in the range [0,1] + /// c0 and a0 are the positions at alpha0. + float32 alpha0; +}; + +/// Useful constant +extern const b2Vec2 b2Vec2_zero; + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.x + a.y * b.y; +} + +/// Perform the cross product on two vectors. In 2D this produces a scalar. +inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.y - a.y * b.x; +} + +/// Perform the cross product on a vector and a scalar. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) +{ + return b2Vec2(s * a.y, -s * a.x); +} + +/// Perform the cross product on a scalar and a vector. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) +{ + return b2Vec2(-s * a.y, s * a.x); +} + +/// Multiply a matrix times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another. +inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another (inverse transform). +inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); +} + +/// Add two vectors component-wise. +inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x + b.x, a.y + b.y); +} + +/// Subtract two vectors component-wise. +inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x - b.x, a.y - b.y); +} + +inline b2Vec2 operator * (float32 s, const b2Vec2& a) +{ + return b2Vec2(s * a.x, s * a.y); +} + +inline bool operator == (const b2Vec2& a, const b2Vec2& b) +{ + return a.x == b.x && a.y == b.y; +} + +inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return c.Length(); +} + +inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return b2Dot(c, c); +} + +inline b2Vec3 operator * (float32 s, const b2Vec3& a) +{ + return b2Vec3(s * a.x, s * a.y, s * a.z); +} + +/// Add two vectors component-wise. +inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +/// Subtract two vectors component-wise. +inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +/// Perform the cross product on two vectors. +inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(A.ex + B.ex, A.ey + B.ey); +} + +// A * B +inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); +} + +// A^T * B +inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) +{ + b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); + b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); + return b2Mat22(c1, c2); +} + +/// Multiply a matrix times a vector. +inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) +{ + return v.x * A.ex + v.y * A.ey + v.z * A.ez; +} + +/// Multiply a matrix times a vector. +inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply two rotations: q * r +inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) +{ + // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] + // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] + // s = qs * rc + qc * rs + // c = qc * rc - qs * rs + b2Rot qr; + qr.s = q.s * r.c + q.c * r.s; + qr.c = q.c * r.c - q.s * r.s; + return qr; +} + +/// Transpose multiply two rotations: qT * r +inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) +{ + // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] + // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] + // s = qc * rs - qs * rc + // c = qc * rc + qs * rs + b2Rot qr; + qr.s = q.c * r.s - q.s * r.c; + qr.c = q.c * r.c + q.s * r.s; + return qr; +} + +/// Rotate a vector +inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); +} + +/// Inverse rotate a vector +inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); +} + +inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) +{ + float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; + float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; + + return b2Vec2(x, y); +} + +inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) +{ + float32 px = v.x - T.p.x; + float32 py = v.y - T.p.y; + float32 x = (T.q.c * px + T.q.s * py); + float32 y = (-T.q.s * px + T.q.c * py); + + return b2Vec2(x, y); +} + +// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p +// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p +inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2Mul(A.q, B.q); + C.p = b2Mul(A.q, B.p) + A.p; + return C; +} + +// v2 = A.q' * (B.q * v1 + B.p - A.p) +// = A.q' * B.q * v1 + A.q' * (B.p - A.p) +inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2MulT(A.q, B.q); + C.p = b2MulT(A.q, B.p - A.p); + return C; +} + +template +inline T b2Abs(T a) +{ + return a > T(0) ? a : -a; +} + +inline b2Vec2 b2Abs(const b2Vec2& a) +{ + return b2Vec2(b2Abs(a.x), b2Abs(a.y)); +} + +inline b2Mat22 b2Abs(const b2Mat22& A) +{ + return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); +} + +template +inline T b2Min(T a, T b) +{ + return a < b ? a : b; +} + +inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); +} + +template +inline T b2Max(T a, T b) +{ + return a > b ? a : b; +} + +inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); +} + +template +inline T b2Clamp(T a, T low, T high) +{ + return b2Max(low, b2Min(a, high)); +} + +inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) +{ + return b2Max(low, b2Min(a, high)); +} + +template inline void b2Swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + +/// "Next Largest Power of 2 +/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm +/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with +/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next +/// largest power of 2. For a 32-bit value:" +inline uint32 b2NextPowerOfTwo(uint32 x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +inline bool b2IsPowerOfTwo(uint32 x) +{ + bool result = x > 0 && (x & (x - 1)) == 0; + return result; +} + +inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const +{ + xf->p = (1.0f - beta) * c0 + beta * c; + float32 angle = (1.0f - beta) * a0 + beta * a; + xf->q.Set(angle); + + // Shift to origin + xf->p -= b2Mul(xf->q, localCenter); +} + +inline void b2Sweep::Advance(float32 alpha) +{ + b2Assert(alpha0 < 1.0f); + float32 beta = (alpha - alpha0) / (1.0f - alpha0); + c0 = (1.0f - beta) * c0 + beta * c; + a0 = (1.0f - beta) * a0 + beta * a; + alpha0 = alpha; +} + +/// Normalize an angle in radians to be between -pi and pi +inline void b2Sweep::Normalize() +{ + float32 twoPi = 2.0f * b2_pi; + float32 d = twoPi * floorf(a0 / twoPi); + a0 -= d; + a -= d; +} + +#endif diff --git a/external/box2d/Common/b2Settings.cpp b/external/box2d/Common/b2Settings.cpp new file mode 100644 index 0000000000..84d6f1d0e4 --- /dev/null +++ b/external/box2d/Common/b2Settings.cpp @@ -0,0 +1,61 @@ +/* +* Copyright (c) 2006-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 +#ifdef SHP +#include +#include +#include +#include +#else +#include +#include +#include +#endif + + +using namespace std; + + +b2Version b2_version = {2, 2, 1}; + +// Memory allocators. Modify these to use your own allocator. +void* b2Alloc(int32 size) +{ + return malloc(size); +} + +void b2Free(void* mem) +{ + free(mem); +} + +// You can modify this to use your logging facility. +void b2Log(const char* string, ...) +{ +#if defined(SHP) + #ifdef _DEBUG + __App_info(__PRETTY_FUNCTION__ , __LINE__, string); + #endif +#else + va_list args; + va_start(args, string); + vprintf(string, args); + va_end(args); +#endif +} diff --git a/external/box2d/Common/b2Settings.h b/external/box2d/Common/b2Settings.h new file mode 100644 index 0000000000..aaf4b12ccf --- /dev/null +++ b/external/box2d/Common/b2Settings.h @@ -0,0 +1,150 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_SETTINGS_H +#define B2_SETTINGS_H + +#include +#include + +#define B2_NOT_USED(x) ((void)(x)) +#define b2Assert(A) assert(A) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef float float32; +typedef double float64; + +#define b2_maxFloat FLT_MAX +#define b2_epsilon FLT_EPSILON +#define b2_pi 3.14159265359f + +/// @file +/// Global tuning constants based on meters-kilograms-seconds (MKS) units. +/// + +// Collision + +/// The maximum number of contact points between two convex shapes. Do +/// not change this value. +#define b2_maxManifoldPoints 2 + +/// The maximum number of vertices on a convex polygon. You cannot increase +/// this too much because b2BlockAllocator has a maximum object size. +#define b2_maxPolygonVertices 8 + +/// This is used to fatten AABBs in the dynamic tree. This allows proxies +/// to move by a small amount without triggering a tree adjustment. +/// This is in meters. +#define b2_aabbExtension 0.1f + +/// This is used to fatten AABBs in the dynamic tree. This is used to predict +/// the future position based on the current displacement. +/// This is a dimensionless multiplier. +#define b2_aabbMultiplier 2.0f + +/// A small length used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_linearSlop 0.005f + +/// A small angle used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_angularSlop (2.0f / 180.0f * b2_pi) + +/// The radius of the polygon/edge shape skin. This should not be modified. Making +/// this smaller means polygons will have an insufficient buffer for continuous collision. +/// Making it larger may create artifacts for vertex collision. +#define b2_polygonRadius (2.0f * b2_linearSlop) + +/// Maximum number of sub-steps per contact in continuous physics simulation. +#define b2_maxSubSteps 8 + + +// Dynamics + +/// Maximum number of contacts to be handled to solve a TOI impact. +#define b2_maxTOIContacts 32 + +/// A velocity threshold for elastic collisions. Any collision with a relative linear +/// velocity below this threshold will be treated as inelastic. +#define b2_velocityThreshold 1.0f + +/// The maximum linear position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxLinearCorrection 0.2f + +/// The maximum angular position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) + +/// The maximum linear velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxTranslation 2.0f +#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) + +/// The maximum angular velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxRotation (0.5f * b2_pi) +#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) + +/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so +/// that overlap is removed in one time step. However using values close to 1 often lead +/// to overshoot. +#define b2_baumgarte 0.2f +#define b2_toiBaugarte 0.75f + + +// Sleep + +/// The time that a body must be still before it will go to sleep. +#define b2_timeToSleep 0.5f + +/// A body cannot sleep if its linear velocity is above this tolerance. +#define b2_linearSleepTolerance 0.01f + +/// A body cannot sleep if its angular velocity is above this tolerance. +#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) + +// Memory Allocation + +/// Implement this function to use your own memory allocator. +void* b2Alloc(int32 size); + +/// If you implement b2Alloc, you should also implement this function. +void b2Free(void* mem); + +/// Logging function. +void b2Log(const char* string, ...); + +/// Version numbering scheme. +/// See http://en.wikipedia.org/wiki/Software_versioning +struct b2Version +{ + int32 major; ///< significant changes + int32 minor; ///< incremental changes + int32 revision; ///< bug fixes +}; + +/// Current version. +extern b2Version b2_version; + +#endif diff --git a/external/box2d/Common/b2StackAllocator.cpp b/external/box2d/Common/b2StackAllocator.cpp new file mode 100644 index 0000000000..3caa5d9127 --- /dev/null +++ b/external/box2d/Common/b2StackAllocator.cpp @@ -0,0 +1,83 @@ +/* +* Copyright (c) 2006-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 +#include + +b2StackAllocator::b2StackAllocator() +{ + m_index = 0; + m_allocation = 0; + m_maxAllocation = 0; + m_entryCount = 0; +} + +b2StackAllocator::~b2StackAllocator() +{ + b2Assert(m_index == 0); + b2Assert(m_entryCount == 0); +} + +void* b2StackAllocator::Allocate(int32 size) +{ + b2Assert(m_entryCount < b2_maxStackEntries); + + b2StackEntry* entry = m_entries + m_entryCount; + entry->size = size; + if (m_index + size > b2_stackSize) + { + entry->data = (char*)b2Alloc(size); + entry->usedMalloc = true; + } + else + { + entry->data = m_data + m_index; + entry->usedMalloc = false; + m_index += size; + } + + m_allocation += size; + m_maxAllocation = b2Max(m_maxAllocation, m_allocation); + ++m_entryCount; + + return entry->data; +} + +void b2StackAllocator::Free(void* p) +{ + b2Assert(m_entryCount > 0); + b2StackEntry* entry = m_entries + m_entryCount - 1; + b2Assert(p == entry->data); + if (entry->usedMalloc) + { + b2Free(p); + } + else + { + m_index -= entry->size; + } + m_allocation -= entry->size; + --m_entryCount; + + p = NULL; +} + +int32 b2StackAllocator::GetMaxAllocation() const +{ + return m_maxAllocation; +} diff --git a/external/box2d/Common/b2StackAllocator.h b/external/box2d/Common/b2StackAllocator.h new file mode 100644 index 0000000000..6140d0d802 --- /dev/null +++ b/external/box2d/Common/b2StackAllocator.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_STACK_ALLOCATOR_H +#define B2_STACK_ALLOCATOR_H + +#include + +const int32 b2_stackSize = 100 * 1024; // 100k +const int32 b2_maxStackEntries = 32; + +struct b2StackEntry +{ + char* data; + int32 size; + bool usedMalloc; +}; + +// This is a stack allocator used for fast per step allocations. +// You must nest allocate/free pairs. The code will assert +// if you try to interleave multiple allocate/free pairs. +class b2StackAllocator +{ +public: + b2StackAllocator(); + ~b2StackAllocator(); + + void* Allocate(int32 size); + void Free(void* p); + + int32 GetMaxAllocation() const; + +private: + + char m_data[b2_stackSize]; + int32 m_index; + + int32 m_allocation; + int32 m_maxAllocation; + + b2StackEntry m_entries[b2_maxStackEntries]; + int32 m_entryCount; +}; + +#endif diff --git a/external/box2d/Common/b2Timer.cpp b/external/box2d/Common/b2Timer.cpp new file mode 100644 index 0000000000..b2bee94513 --- /dev/null +++ b/external/box2d/Common/b2Timer.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +#if defined(_WIN32) && !defined(SHP) + +float64 b2Timer::s_invFrequency = 0.0f; + +#include + +b2Timer::b2Timer() +{ + LARGE_INTEGER largeInteger; + + if (s_invFrequency == 0.0f) + { + QueryPerformanceFrequency(&largeInteger); + s_invFrequency = float64(largeInteger.QuadPart); + if (s_invFrequency > 0.0f) + { + s_invFrequency = 1000.0f / s_invFrequency; + } + } + + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +void b2Timer::Reset() +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +float32 b2Timer::GetMilliseconds() const +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + float64 count = float64(largeInteger.QuadPart); + float32 ms = float32(s_invFrequency * (count - m_start)); + return ms; +} + +#elif defined(__linux__) || defined (__APPLE__) + +#include + +b2Timer::b2Timer() +{ + Reset(); +} + +void b2Timer::Reset() +{ + timeval t; + gettimeofday(&t, 0); + m_start_sec = t.tv_sec; + m_start_msec = t.tv_usec * 0.001f; +} + +float32 b2Timer::GetMilliseconds() const +{ + timeval t; + gettimeofday(&t, 0); + return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; +} + +#else + +b2Timer::b2Timer() +{ +} + +void b2Timer::Reset() +{ +} + +float32 b2Timer::GetMilliseconds() const +{ + return 0.0f; +} + +#endif diff --git a/external/box2d/Common/b2Timer.h b/external/box2d/Common/b2Timer.h new file mode 100644 index 0000000000..053a107a56 --- /dev/null +++ b/external/box2d/Common/b2Timer.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +/// Timer for profiling. This has platform specific code and may +/// not work on every platform. +class b2Timer +{ +public: + + /// Constructor + b2Timer(); + + /// Reset the timer. + void Reset(); + + /// Get the time since construction or the last reset. + float32 GetMilliseconds() const; + +private: + +#if defined(_WIN32) + float64 m_start; + static float64 s_invFrequency; +#elif defined(__linux__) || defined (__APPLE__) + unsigned long m_start_sec; + unsigned long m_start_msec; +#endif +}; diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp new file mode 100644 index 0000000000..4ae4c41cd3 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); + return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); + allocator->Free(contact, sizeof(b2ChainAndCircleContact)); +} + +b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndCircle( manifold, &edge, xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h new file mode 100644 index 0000000000..1cf601a61f --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H +#define B2_CHAIN_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp new file mode 100644 index 0000000000..8116c34d1b --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); + return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); + allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); +} + +b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndPolygon( manifold, &edge, xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h new file mode 100644 index 0000000000..381c49b844 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H +#define B2_CHAIN_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2CircleContact.cpp b/external/box2d/Dynamics/Contacts/b2CircleContact.cpp new file mode 100644 index 0000000000..2436da5132 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2CircleContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2CircleContact)); + return new (mem) b2CircleContact(fixtureA, fixtureB); +} + +void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2CircleContact*)contact)->~b2CircleContact(); + allocator->Free(contact, sizeof(b2CircleContact)); +} + +b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideCircles(manifold, + (b2CircleShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2CircleContact.h b/external/box2d/Dynamics/Contacts/b2CircleContact.h new file mode 100644 index 0000000000..6da056ae0d --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2CircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CIRCLE_CONTACT_H +#define B2_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2CircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2CircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2Contact.cpp b/external/box2d/Dynamics/Contacts/b2Contact.cpp new file mode 100644 index 0000000000..2389af6434 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2Contact.cpp @@ -0,0 +1,240 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; +bool b2Contact::s_initialized = false; + +void b2Contact::InitializeRegisters() +{ + AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); + AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); + AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); + AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); + AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); + AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); + AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); +} + +void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, + b2Shape::Type type1, b2Shape::Type type2) +{ + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + s_registers[type1][type2].createFcn = createFcn; + s_registers[type1][type2].destroyFcn = destoryFcn; + s_registers[type1][type2].primary = true; + + if (type1 != type2) + { + s_registers[type2][type1].createFcn = createFcn; + s_registers[type2][type1].destroyFcn = destoryFcn; + s_registers[type2][type1].primary = false; + } +} + +b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + if (s_initialized == false) + { + InitializeRegisters(); + s_initialized = true; + } + + b2Shape::Type type1 = fixtureA->GetType(); + b2Shape::Type type2 = fixtureB->GetType(); + + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; + if (createFcn) + { + if (s_registers[type1][type2].primary) + { + return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); + } + else + { + return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); + } + } + else + { + return NULL; + } +} + +void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + b2Assert(s_initialized == true); + + if (contact->m_manifold.pointCount > 0) + { + contact->GetFixtureA()->GetBody()->SetAwake(true); + contact->GetFixtureB()->GetBody()->SetAwake(true); + } + + b2Shape::Type typeA = contact->GetFixtureA()->GetType(); + b2Shape::Type typeB = contact->GetFixtureB()->GetType(); + + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + + b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; + destroyFcn(contact, allocator); +} + +b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) +{ + m_flags = e_enabledFlag; + + m_fixtureA = fA; + m_fixtureB = fB; + + m_indexA = indexA; + m_indexB = indexB; + + m_manifold.pointCount = 0; + + m_prev = NULL; + m_next = NULL; + + m_nodeA.contact = NULL; + m_nodeA.prev = NULL; + m_nodeA.next = NULL; + m_nodeA.other = NULL; + + m_nodeB.contact = NULL; + m_nodeB.prev = NULL; + m_nodeB.next = NULL; + m_nodeB.other = NULL; + + m_toiCount = 0; + + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +// Update the contact manifold and touching status. +// Note: do not assume the fixture AABBs are overlapping or are valid. +void b2Contact::Update(b2ContactListener* listener) +{ + b2Manifold oldManifold = m_manifold; + + // Re-enable this contact. + m_flags |= e_enabledFlag; + + bool touching = false; + bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; + + bool sensorA = m_fixtureA->IsSensor(); + bool sensorB = m_fixtureB->IsSensor(); + bool sensor = sensorA || sensorB; + + b2Body* bodyA = m_fixtureA->GetBody(); + b2Body* bodyB = m_fixtureB->GetBody(); + const b2Transform& xfA = bodyA->GetTransform(); + const b2Transform& xfB = bodyB->GetTransform(); + + // Is this contact a sensor? + if (sensor) + { + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); + + // Sensors don't generate manifolds. + m_manifold.pointCount = 0; + } + else + { + Evaluate(&m_manifold, xfA, xfB); + touching = m_manifold.pointCount > 0; + + // Match old contact ids to new contact ids and copy the + // stored impulses to warm start the solver. + for (int32 i = 0; i < m_manifold.pointCount; ++i) + { + b2ManifoldPoint* mp2 = m_manifold.points + i; + mp2->normalImpulse = 0.0f; + mp2->tangentImpulse = 0.0f; + b2ContactID id2 = mp2->id; + + for (int32 j = 0; j < oldManifold.pointCount; ++j) + { + b2ManifoldPoint* mp1 = oldManifold.points + j; + + if (mp1->id.key == id2.key) + { + mp2->normalImpulse = mp1->normalImpulse; + mp2->tangentImpulse = mp1->tangentImpulse; + break; + } + } + } + + if (touching != wasTouching) + { + bodyA->SetAwake(true); + bodyB->SetAwake(true); + } + } + + if (touching) + { + m_flags |= e_touchingFlag; + } + else + { + m_flags &= ~e_touchingFlag; + } + + if (wasTouching == false && touching == true && listener) + { + listener->BeginContact(this); + } + + if (wasTouching == true && touching == false && listener) + { + listener->EndContact(this); + } + + if (sensor == false && touching && listener) + { + listener->PreSolve(this, &oldManifold); + } +} diff --git a/external/box2d/Dynamics/Contacts/b2Contact.h b/external/box2d/Dynamics/Contacts/b2Contact.h new file mode 100644 index 0000000000..20d9403ce7 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2Contact.h @@ -0,0 +1,331 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_H +#define B2_CONTACT_H + +#include +#include +#include +#include + +class b2Body; +class b2Contact; +class b2Fixture; +class b2World; +class b2BlockAllocator; +class b2StackAllocator; +class b2ContactListener; + +/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. +/// For example, anything slides on ice. +inline float32 b2MixFriction(float32 friction1, float32 friction2) +{ + return std::sqrt(friction1 * friction2); +} + +/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. +/// For example, a superball bounces on anything. +inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) +{ + return restitution1 > restitution2 ? restitution1 : restitution2; +} + +typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, + b2BlockAllocator* allocator); +typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); + +struct b2ContactRegister +{ + b2ContactCreateFcn* createFcn; + b2ContactDestroyFcn* destroyFcn; + bool primary; +}; + +/// A contact edge is used to connect bodies and contacts together +/// in a contact graph where each body is a node and each contact +/// is an edge. A contact edge belongs to a doubly linked list +/// maintained in each attached body. Each contact has two contact +/// nodes, one for each attached body. +struct b2ContactEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Contact* contact; ///< the contact + b2ContactEdge* prev; ///< the previous contact edge in the body's contact list + b2ContactEdge* next; ///< the next contact edge in the body's contact list +}; + +/// The class manages contact between two shapes. A contact exists for each overlapping +/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist +/// that has no contact points. +class b2Contact +{ +public: + + /// Get the contact manifold. Do not modify the manifold unless you understand the + /// internals of Box2D. + b2Manifold* GetManifold(); + const b2Manifold* GetManifold() const; + + /// Get the world manifold. + void GetWorldManifold(b2WorldManifold* worldManifold) const; + + /// Is this contact touching? + bool IsTouching() const; + + /// Enable/disable this contact. This can be used inside the pre-solve + /// contact listener. The contact is only disabled for the current + /// time step (or sub-step in continuous collisions). + void SetEnabled(bool flag); + + /// Has this contact been disabled? + bool IsEnabled() const; + + /// Get the next contact in the world's contact list. + b2Contact* GetNext(); + const b2Contact* GetNext() const; + + /// Get fixture A in this contact. + b2Fixture* GetFixtureA(); + const b2Fixture* GetFixtureA() const; + + /// Get the child primitive index for fixture A. + int32 GetChildIndexA() const; + + /// Get fixture B in this contact. + b2Fixture* GetFixtureB(); + const b2Fixture* GetFixtureB() const; + + /// Get the child primitive index for fixture B. + int32 GetChildIndexB() const; + + /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. + /// This value persists until set or reset. + void SetFriction(float32 friction); + + /// Get the friction. + float32 GetFriction() const; + + /// Reset the friction mixture to the default value. + void ResetFriction(); + + /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. + /// The value persists until you set or reset. + void SetRestitution(float32 restitution); + + /// Get the restitution. + float32 GetRestitution() const; + + /// Reset the restitution to the default value. + void ResetRestitution(); + + /// Evaluate this contact with your own manifold and transforms. + virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; + +protected: + friend class b2ContactManager; + friend class b2World; + friend class b2ContactSolver; + friend class b2Body; + friend class b2Fixture; + + // Flags stored in m_flags + enum + { + // Used when crawling contact graph when forming islands. + e_islandFlag = 0x0001, + + // Set when the shapes are touching. + e_touchingFlag = 0x0002, + + // This contact can be disabled (by user) + e_enabledFlag = 0x0004, + + // This contact needs filtering because a fixture filter was changed. + e_filterFlag = 0x0008, + + // This bullet contact had a TOI event + e_bulletHitFlag = 0x0010, + + // This contact has a valid TOI in m_toi + e_toiFlag = 0x0020 + }; + + /// Flag this contact for filtering. Filtering will occur the next time step. + void FlagForFiltering(); + + static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, + b2Shape::Type typeA, b2Shape::Type typeB); + static void InitializeRegisters(); + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} + b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + virtual ~b2Contact() {} + + void Update(b2ContactListener* listener); + + static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; + static bool s_initialized; + + uint32 m_flags; + + // World pool and list pointers. + b2Contact* m_prev; + b2Contact* m_next; + + // Nodes for connecting bodies. + b2ContactEdge m_nodeA; + b2ContactEdge m_nodeB; + + b2Fixture* m_fixtureA; + b2Fixture* m_fixtureB; + + int32 m_indexA; + int32 m_indexB; + + b2Manifold m_manifold; + + int32 m_toiCount; + float32 m_toi; + + float32 m_friction; + float32 m_restitution; +}; + +inline b2Manifold* b2Contact::GetManifold() +{ + return &m_manifold; +} + +inline const b2Manifold* b2Contact::GetManifold() const +{ + return &m_manifold; +} + +inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const +{ + const b2Body* bodyA = m_fixtureA->GetBody(); + const b2Body* bodyB = m_fixtureB->GetBody(); + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + + worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); +} + +inline void b2Contact::SetEnabled(bool flag) +{ + if (flag) + { + m_flags |= e_enabledFlag; + } + else + { + m_flags &= ~e_enabledFlag; + } +} + +inline bool b2Contact::IsEnabled() const +{ + return (m_flags & e_enabledFlag) == e_enabledFlag; +} + +inline bool b2Contact::IsTouching() const +{ + return (m_flags & e_touchingFlag) == e_touchingFlag; +} + +inline b2Contact* b2Contact::GetNext() +{ + return m_next; +} + +inline const b2Contact* b2Contact::GetNext() const +{ + return m_next; +} + +inline b2Fixture* b2Contact::GetFixtureA() +{ + return m_fixtureA; +} + +inline const b2Fixture* b2Contact::GetFixtureA() const +{ + return m_fixtureA; +} + +inline b2Fixture* b2Contact::GetFixtureB() +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexA() const +{ + return m_indexA; +} + +inline const b2Fixture* b2Contact::GetFixtureB() const +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexB() const +{ + return m_indexB; +} + +inline void b2Contact::FlagForFiltering() +{ + m_flags |= e_filterFlag; +} + +inline void b2Contact::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Contact::GetFriction() const +{ + return m_friction; +} + +inline void b2Contact::ResetFriction() +{ + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); +} + +inline void b2Contact::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline float32 b2Contact::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Contact::ResetRestitution() +{ + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp b/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp new file mode 100644 index 0000000000..0dc740342a --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp @@ -0,0 +1,832 @@ +/* +* Copyright (c) 2006-2011 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 + +#include +#include +#include +#include +#include + +#define B2_DEBUG_SOLVER 0 + +struct b2ContactPositionConstraint +{ + b2Vec2 localPoints[b2_maxManifoldPoints]; + b2Vec2 localNormal; + b2Vec2 localPoint; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + b2Vec2 localCenterA, localCenterB; + float32 invIA, invIB; + b2Manifold::Type type; + float32 radiusA, radiusB; + int32 pointCount; +}; + +b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) +{ + m_step = def->step; + m_allocator = def->allocator; + m_count = def->count; + m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); + m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); + m_positions = def->positions; + m_velocities = def->velocities; + m_contacts = def->contacts; + + // Initialize position independent portions of the constraints. + for (int32 i = 0; i < m_count; ++i) + { + b2Contact* contact = m_contacts[i]; + + b2Fixture* fixtureA = contact->m_fixtureA; + b2Fixture* fixtureB = contact->m_fixtureB; + b2Shape* shapeA = fixtureA->GetShape(); + b2Shape* shapeB = fixtureB->GetShape(); + float32 radiusA = shapeA->m_radius; + float32 radiusB = shapeB->m_radius; + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + b2Manifold* manifold = contact->GetManifold(); + + int32 pointCount = manifold->pointCount; + b2Assert(pointCount > 0); + + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + vc->friction = contact->m_friction; + vc->restitution = contact->m_restitution; + vc->indexA = bodyA->m_islandIndex; + vc->indexB = bodyB->m_islandIndex; + vc->invMassA = bodyA->m_invMass; + vc->invMassB = bodyB->m_invMass; + vc->invIA = bodyA->m_invI; + vc->invIB = bodyB->m_invI; + vc->contactIndex = i; + vc->pointCount = pointCount; + vc->K.SetZero(); + vc->normalMass.SetZero(); + + b2ContactPositionConstraint* pc = m_positionConstraints + i; + pc->indexA = bodyA->m_islandIndex; + pc->indexB = bodyB->m_islandIndex; + pc->invMassA = bodyA->m_invMass; + pc->invMassB = bodyB->m_invMass; + pc->localCenterA = bodyA->m_sweep.localCenter; + pc->localCenterB = bodyB->m_sweep.localCenter; + pc->invIA = bodyA->m_invI; + pc->invIB = bodyB->m_invI; + pc->localNormal = manifold->localNormal; + pc->localPoint = manifold->localPoint; + pc->pointCount = pointCount; + pc->radiusA = radiusA; + pc->radiusB = radiusB; + pc->type = manifold->type; + + for (int32 j = 0; j < pointCount; ++j) + { + b2ManifoldPoint* cp = manifold->points + j; + b2VelocityConstraintPoint* vcp = vc->points + j; + + if (m_step.warmStarting) + { + vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; + vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; + } + else + { + vcp->normalImpulse = 0.0f; + vcp->tangentImpulse = 0.0f; + } + + vcp->rA.SetZero(); + vcp->rB.SetZero(); + vcp->normalMass = 0.0f; + vcp->tangentMass = 0.0f; + vcp->velocityBias = 0.0f; + + pc->localPoints[j] = cp->localPoint; + } + } +} + +b2ContactSolver::~b2ContactSolver() +{ + m_allocator->Free(m_velocityConstraints); + m_allocator->Free(m_positionConstraints); +} + +// Initialize position dependent portions of the velocity constraints. +void b2ContactSolver::InitializeVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + float32 radiusA = pc->radiusA; + float32 radiusB = pc->radiusB; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + + float32 mA = vc->invMassA; + float32 mB = vc->invMassB; + float32 iA = vc->invIA; + float32 iB = vc->invIB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Assert(manifold->pointCount > 0); + + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2WorldManifold worldManifold; + worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); + + vc->normal = worldManifold.normal; + + int32 pointCount = vc->pointCount; + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + vcp->rA = worldManifold.points[j] - cA; + vcp->rB = worldManifold.points[j] - cB; + + float32 rnA = b2Cross(vcp->rA, vc->normal); + float32 rnB = b2Cross(vcp->rB, vc->normal); + + float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; + + b2Vec2 tangent = b2Cross(vc->normal, 1.0f); + + float32 rtA = b2Cross(vcp->rA, tangent); + float32 rtB = b2Cross(vcp->rB, tangent); + + float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; + + vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; + + // Setup a velocity bias for restitution. + vcp->velocityBias = 0.0f; + float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); + if (vRel < -b2_velocityThreshold) + { + vcp->velocityBias = -vc->restitution * vRel; + } + } + + // If we have two points, then prepare the block solver. + if (vc->pointCount == 2) + { + b2VelocityConstraintPoint* vcp1 = vc->points + 0; + b2VelocityConstraintPoint* vcp2 = vc->points + 1; + + float32 rn1A = b2Cross(vcp1->rA, vc->normal); + float32 rn1B = b2Cross(vcp1->rB, vc->normal); + float32 rn2A = b2Cross(vcp2->rA, vc->normal); + float32 rn2B = b2Cross(vcp2->rB, vc->normal); + + float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; + float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; + float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; + + // Ensure a reasonable condition number. + const float32 k_maxConditionNumber = 1000.0f; + if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) + { + // K is safe to invert. + vc->K.ex.Set(k11, k12); + vc->K.ey.Set(k12, k22); + vc->normalMass = vc->K.GetInverse(); + } + else + { + // The constraints are redundant, just use one. + // TODO_ERIN use deepest? + vc->pointCount = 1; + } + } + } +} + +void b2ContactSolver::WarmStart() +{ + // Warm start. + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; + wA -= iA * b2Cross(vcp->rA, P); + vA -= mA * P; + wB += iB * b2Cross(vcp->rB, P); + vB += mB * P; + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::SolveVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + float32 friction = vc->friction; + + b2Assert(pointCount == 1 || pointCount == 2); + + // Solve tangent constraints first because non-penetration is more important + // than friction. + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute tangent force + float32 vt = b2Dot(dv, tangent); + float32 lambda = vcp->tangentMass * (-vt); + + // b2Clamp the accumulated force + float32 maxFriction = friction * vcp->normalImpulse; + float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); + lambda = newImpulse - vcp->tangentImpulse; + vcp->tangentImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * tangent; + + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + + // Solve normal constraints + if (vc->pointCount == 1) + { + b2VelocityConstraintPoint* vcp = vc->points + 0; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute normal impulse + float32 vn = b2Dot(dv, normal); + float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); + + // b2Clamp the accumulated impulse + float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); + lambda = newImpulse - vcp->normalImpulse; + vcp->normalImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * normal; + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + else + { + // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). + // Build the mini LCP for this contact patch + // + // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 + // + // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) + // b = vn0 - velocityBias + // + // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i + // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases + // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid + // solution that satisfies the problem is chosen. + // + // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires + // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). + // + // Substitute: + // + // x = a + d + // + // a := old total impulse + // x := new total impulse + // d := incremental impulse + // + // For the current iteration we extend the formula for the incremental impulse + // to compute the new total impulse: + // + // vn = A * d + b + // = A * (x - a) + b + // = A * x + b - A * a + // = A * x + b' + // b' = b - A * a; + + b2VelocityConstraintPoint* cp1 = vc->points + 0; + b2VelocityConstraintPoint* cp2 = vc->points + 1; + + b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); + b2Assert(a.x >= 0.0f && a.y >= 0.0f); + + // Relative velocity at contact + b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + float32 vn1 = b2Dot(dv1, normal); + float32 vn2 = b2Dot(dv2, normal); + + b2Vec2 b; + b.x = vn1 - cp1->velocityBias; + b.y = vn2 - cp2->velocityBias; + + // Compute b' + b -= b2Mul(vc->K, a); + + const float32 k_errorTol = 1e-3f; + B2_NOT_USED(k_errorTol); + + for (;;) + { + // + // Case 1: vn = 0 + // + // 0 = A * x + b' + // + // Solve for x: + // + // x = - inv(A) * b' + // + b2Vec2 x = - b2Mul(vc->normalMass, b); + + if (x.x >= 0.0f && x.y >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 2: vn1 = 0 and x2 = 0 + // + // 0 = a11 * x1 + a12 * 0 + b1' + // vn2 = a21 * x1 + a22 * 0 + b2' + // + x.x = - cp1->normalMass * b.x; + x.y = 0.0f; + vn1 = 0.0f; + vn2 = vc->K.ex.y * x.x + b.y; + + if (x.x >= 0.0f && vn2 >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); +#endif + break; + } + + + // + // Case 3: vn2 = 0 and x1 = 0 + // + // vn1 = a11 * 0 + a12 * x2 + b1' + // 0 = a21 * 0 + a22 * x2 + b2' + // + x.x = 0.0f; + x.y = - cp2->normalMass * b.y; + vn1 = vc->K.ey.x * x.y + b.x; + vn2 = 0.0f; + + if (x.y >= 0.0f && vn1 >= 0.0f) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 4: x1 = 0 and x2 = 0 + // + // vn1 = b1 + // vn2 = b2; + x.x = 0.0f; + x.y = 0.0f; + vn1 = b.x; + vn2 = b.y; + + if (vn1 >= 0.0f && vn2 >= 0.0f ) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + + break; + } + + // No solution, give up. This is hit sometimes, but it doesn't seem to matter. + break; + } + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::StoreImpulses() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + for (int32 j = 0; j < vc->pointCount; ++j) + { + manifold->points[j].normalImpulse = vc->points[j].normalImpulse; + manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; + } + } +} + +struct b2PositionSolverManifold +{ + void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) + { + b2Assert(pc->pointCount > 0); + + switch (pc->type) + { + case b2Manifold::e_circles: + { + b2Vec2 pointA = b2Mul(xfA, pc->localPoint); + b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); + normal = pointB - pointA; + normal.Normalize(); + point = 0.5f * (pointA + pointB); + separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; + } + break; + + case b2Manifold::e_faceA: + { + normal = b2Mul(xfA.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + } + break; + + case b2Manifold::e_faceB: + { + normal = b2Mul(xfB.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + + // Ensure normal points from A to B + normal = -normal; + } + break; + } + } + + b2Vec2 normal; + b2Vec2 point; + float32 separation; +}; + +// Sequential solver. +bool b2ContactSolver::SolvePositionConstraints() +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + float32 mA = pc->invMassA; + float32 iA = pc->invIA; + b2Vec2 localCenterB = pc->localCenterB; + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + int32 pointCount = pc->pointCount; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -3.0f * b2_linearSlop; +} + +// Sequential position solver for position constraints. +bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + int32 pointCount = pc->pointCount; + + float32 mA = 0.0f; + float32 iA = 0.0f; + if (indexA == toiIndexA || indexA == toiIndexB) + { + mA = pc->invMassA; + iA = pc->invIA; + } + + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + if (indexB == toiIndexA || indexB == toiIndexB) + { + mB = pc->invMassB; + iB = pc->invIB; + } + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -1.5f * b2_linearSlop; +} diff --git a/external/box2d/Dynamics/Contacts/b2ContactSolver.h b/external/box2d/Dynamics/Contacts/b2ContactSolver.h new file mode 100644 index 0000000000..aef1987a9e --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2ContactSolver.h @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_SOLVER_H +#define B2_CONTACT_SOLVER_H + +#include +#include +#include + +class b2Contact; +class b2Body; +class b2StackAllocator; +struct b2ContactPositionConstraint; + +struct b2VelocityConstraintPoint +{ + b2Vec2 rA; + b2Vec2 rB; + float32 normalImpulse; + float32 tangentImpulse; + float32 normalMass; + float32 tangentMass; + float32 velocityBias; +}; + +struct b2ContactVelocityConstraint +{ + b2VelocityConstraintPoint points[b2_maxManifoldPoints]; + b2Vec2 normal; + b2Mat22 normalMass; + b2Mat22 K; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + float32 invIA, invIB; + float32 friction; + float32 restitution; + int32 pointCount; + int32 contactIndex; +}; + +struct b2ContactSolverDef +{ + b2TimeStep step; + b2Contact** contacts; + int32 count; + b2Position* positions; + b2Velocity* velocities; + b2StackAllocator* allocator; +}; + +class b2ContactSolver +{ +public: + b2ContactSolver(b2ContactSolverDef* def); + ~b2ContactSolver(); + + void InitializeVelocityConstraints(); + + void WarmStart(); + void SolveVelocityConstraints(); + void StoreImpulses(); + + bool SolvePositionConstraints(); + bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); + + b2TimeStep m_step; + b2Position* m_positions; + b2Velocity* m_velocities; + b2StackAllocator* m_allocator; + b2ContactPositionConstraint* m_positionConstraints; + b2ContactVelocityConstraint* m_velocityConstraints; + b2Contact** m_contacts; + int m_count; +}; + +#endif + diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp new file mode 100644 index 0000000000..aade42880a --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); + return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); +} + +void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); + allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); +} + +b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndCircle( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h new file mode 100644 index 0000000000..70771ec536 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H +#define B2_EDGE_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp new file mode 100644 index 0000000000..04ce394107 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); + return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); +} + +void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); + allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); +} + +b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndPolygon( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h new file mode 100644 index 0000000000..f65f3acca9 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_EDGE_AND_POLYGON_CONTACT_H +#define B2_EDGE_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp new file mode 100644 index 0000000000..961b26f38a --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-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 +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); + return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); +} + +void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); + allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); +} + +b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygonAndCircle( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h new file mode 100644 index 0000000000..7b1a5288b4 --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H +#define B2_POLYGON_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp new file mode 100644 index 0000000000..a2884a440d --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonContact)); + return new (mem) b2PolygonContact(fixtureA, fixtureB); +} + +void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonContact*)contact)->~b2PolygonContact(); + allocator->Free(contact, sizeof(b2PolygonContact)); +} + +b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygons( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/box2d/Dynamics/Contacts/b2PolygonContact.h b/external/box2d/Dynamics/Contacts/b2PolygonContact.h new file mode 100644 index 0000000000..302684232a --- /dev/null +++ b/external/box2d/Dynamics/Contacts/b2PolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_CONTACT_H +#define B2_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp b/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp new file mode 100644 index 0000000000..b2d4bd006c --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp @@ -0,0 +1,260 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// 1-D constrained system +// m (v2 - v1) = lambda +// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. +// x2 = x1 + h * v2 + +// 1-D mass-damper-spring system +// m (v2 - v1) + h * d * v2 + h * k * + +// C = norm(p2 - p1) - L +// u = (p2 - p1) / norm(p2 - p1) +// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// J = [-u -cross(r1, u) u cross(r2, u)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 + +void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, + const b2Vec2& anchor1, const b2Vec2& anchor2) +{ + bodyA = b1; + bodyB = b2; + localAnchorA = bodyA->GetLocalPoint(anchor1); + localAnchorB = bodyB->GetLocalPoint(anchor2); + b2Vec2 d = anchor2 - anchor1; + length = d.Length(); +} + +b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_length = def->length; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + m_impulse = 0.0f; + m_gamma = 0.0f; + m_bias = 0.0f; +} + +void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + // Handle singularity. + float32 length = m_u.Length(); + if (length > b2_linearSlop) + { + m_u *= 1.0f / length; + } + else + { + m_u.Set(0.0f, 0.0f); + } + + float32 crAu = b2Cross(m_rA, m_u); + float32 crBu = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; + + // Compute the effective mass matrix. + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (m_frequencyHz > 0.0f) + { + float32 C = length - m_length; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_mass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invMass += m_gamma; + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + } + else + { + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 Cdot = b2Dot(m_u, vpB - vpA); + + float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); + m_impulse += impulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) +{ + if (m_frequencyHz > 0.0f) + { + // There is no position correction for soft distance constraints. + return true; + } + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_length; + C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) < b2_linearSlop; +} + +b2Vec2 b2DistanceJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2DistanceJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +void b2DistanceJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2DistanceJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.length = %.15lef;\n", m_length); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2DistanceJoint.h b/external/box2d/Dynamics/Joints/b2DistanceJoint.h new file mode 100644 index 0000000000..fc11476ff9 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2DistanceJoint.h @@ -0,0 +1,169 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_DISTANCE_JOINT_H +#define B2_DISTANCE_JOINT_H + +#include + +/// Distance joint definition. This requires defining an +/// anchor point on both bodies and the non-zero length of the +/// distance joint. The definition uses local anchor points +/// so that the initial configuration can violate the constraint +/// slightly. This helps when saving and loading a game. +/// @warning Do not use a zero or short length. +struct b2DistanceJointDef : public b2JointDef +{ + b2DistanceJointDef() + { + type = e_distanceJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + length = 1.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and length using the world + /// anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& anchorA, const b2Vec2& anchorB); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The natural length between the anchor points. + float32 length; + + /// The mass-spring-damper frequency in Hertz. A value of 0 + /// disables softness. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A distance joint constrains two points on two bodies +/// to remain at a fixed distance from each other. You can view +/// this as a massless, rigid rod. +class b2DistanceJoint : public b2Joint +{ +public: + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque given the inverse time step. + /// Unit is N*m. This is always zero for a distance joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/get the natural length. + /// Manipulating the length can lead to non-physical behavior when the frequency is zero. + void SetLength(float32 length); + float32 GetLength() const; + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2DistanceJoint(const b2DistanceJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_gamma; + float32 m_impulse; + float32 m_length; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +inline void b2DistanceJoint::SetLength(float32 length) +{ + m_length = length; +} + +inline float32 b2DistanceJoint::GetLength() const +{ + return m_length; +} + +inline void b2DistanceJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2DistanceJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +inline void b2DistanceJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2DistanceJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp b/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp new file mode 100644 index 0000000000..6e6018db10 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp @@ -0,0 +1,251 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); +} + +b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + + m_maxForce = def->maxForce; + m_maxTorque = def->maxTorque; +} + +void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective mass matrix. + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; + K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; + + m_linearMass = K.GetInverse(); + + m_angularMass = iA + iB; + if (m_angularMass > 0.0f) + { + m_angularMass = 1.0f / m_angularMass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_linearImpulse *= data.step.dtRatio; + m_angularImpulse *= data.step.dtRatio; + + b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); + } + else + { + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + float32 h = data.step.dt; + + // Solve angular friction + { + float32 Cdot = wB - wA; + float32 impulse = -m_angularMass * Cdot; + + float32 oldImpulse = m_angularImpulse; + float32 maxImpulse = h * m_maxTorque; + m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_angularImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve linear friction + { + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); + b2Vec2 oldImpulse = m_linearImpulse; + m_linearImpulse += impulse; + + float32 maxImpulse = h * m_maxForce; + + if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_linearImpulse.Normalize(); + m_linearImpulse *= maxImpulse; + } + + impulse = m_linearImpulse - oldImpulse; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + + return true; +} + +b2Vec2 b2FrictionJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2FrictionJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_linearImpulse; +} + +float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_angularImpulse; +} + +void b2FrictionJoint::SetMaxForce(float32 force) +{ + b2Assert(b2IsValid(force) && force >= 0.0f); + m_maxForce = force; +} + +float32 b2FrictionJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2FrictionJoint::SetMaxTorque(float32 torque) +{ + b2Assert(b2IsValid(torque) && torque >= 0.0f); + m_maxTorque = torque; +} + +float32 b2FrictionJoint::GetMaxTorque() const +{ + return m_maxTorque; +} + +void b2FrictionJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2FrictionJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); + b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2FrictionJoint.h b/external/box2d/Dynamics/Joints/b2FrictionJoint.h new file mode 100644 index 0000000000..3ee40c6298 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2FrictionJoint.h @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_FRICTION_JOINT_H +#define B2_FRICTION_JOINT_H + +#include + +/// Friction joint definition. +struct b2FrictionJointDef : public b2JointDef +{ + b2FrictionJointDef() + { + type = e_frictionJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + maxForce = 0.0f; + maxTorque = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum friction force in N. + float32 maxForce; + + /// The maximum friction torque in N-m. + float32 maxTorque; +}; + +/// Friction joint. This is used for top-down friction. +/// It provides 2D translational friction and angular friction. +class b2FrictionJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set the maximum friction force in N. + void SetMaxForce(float32 force); + + /// Get the maximum friction force in N. + float32 GetMaxForce() const; + + /// Set the maximum friction torque in N*m. + void SetMaxTorque(float32 torque); + + /// Get the maximum friction torque in N*m. + float32 GetMaxTorque() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + + b2FrictionJoint(const b2FrictionJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + + // Solver shared + b2Vec2 m_linearImpulse; + float32 m_angularImpulse; + float32 m_maxForce; + float32 m_maxTorque; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat22 m_linearMass; + float32 m_angularMass; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2GearJoint.cpp b/external/box2d/Dynamics/Joints/b2GearJoint.cpp new file mode 100644 index 0000000000..9741cdd5a4 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2GearJoint.cpp @@ -0,0 +1,423 @@ +/* +* Copyright (c) 2007-2011 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 +#include +#include +#include +#include + +// Gear Joint: +// C0 = (coordinate1 + ratio * coordinate2)_initial +// C = (coordinate1 + ratio * coordinate2) - C0 = 0 +// J = [J1 ratio * J2] +// K = J * invM * JT +// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T +// +// Revolute: +// coordinate = rotation +// Cdot = angularVelocity +// J = [0 0 1] +// K = J * invM * JT = invI +// +// Prismatic: +// coordinate = dot(p - pg, ug) +// Cdot = dot(v + cross(w, r), ug) +// J = [ug cross(r, ug)] +// K = J * invM * JT = invMass + invI * cross(r, ug)^2 + +b2GearJoint::b2GearJoint(const b2GearJointDef* def) +: b2Joint(def) +{ + m_joint1 = def->joint1; + m_joint2 = def->joint2; + + m_typeA = m_joint1->GetType(); + m_typeB = m_joint2->GetType(); + + b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); + b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); + + float32 coordinateA, coordinateB; + + // TODO_ERIN there might be some problem with the joint edges in b2Joint. + + m_bodyC = m_joint1->GetBodyA(); + m_bodyA = m_joint1->GetBodyB(); + + // Get geometry of joint1 + b2Transform xfA = m_bodyA->m_xf; + float32 aA = m_bodyA->m_sweep.a; + b2Transform xfC = m_bodyC->m_xf; + float32 aC = m_bodyC->m_sweep.a; + + if (m_typeA == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; + m_localAnchorC = revolute->m_localAnchorA; + m_localAnchorA = revolute->m_localAnchorB; + m_referenceAngleA = revolute->m_referenceAngle; + m_localAxisC.SetZero(); + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; + m_localAnchorC = prismatic->m_localAnchorA; + m_localAnchorA = prismatic->m_localAnchorB; + m_referenceAngleA = prismatic->m_referenceAngle; + m_localAxisC = prismatic->m_localXAxisA; + + b2Vec2 pC = m_localAnchorC; + b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + m_bodyD = m_joint2->GetBodyA(); + m_bodyB = m_joint2->GetBodyB(); + + // Get geometry of joint2 + b2Transform xfB = m_bodyB->m_xf; + float32 aB = m_bodyB->m_sweep.a; + b2Transform xfD = m_bodyD->m_xf; + float32 aD = m_bodyD->m_sweep.a; + + if (m_typeB == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; + m_localAnchorD = revolute->m_localAnchorA; + m_localAnchorB = revolute->m_localAnchorB; + m_referenceAngleB = revolute->m_referenceAngle; + m_localAxisD.SetZero(); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; + m_localAnchorD = prismatic->m_localAnchorA; + m_localAnchorB = prismatic->m_localAnchorB; + m_referenceAngleB = prismatic->m_referenceAngle; + m_localAxisD = prismatic->m_localXAxisA; + + b2Vec2 pD = m_localAnchorD; + b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + m_ratio = def->ratio; + + m_constant = coordinateA + m_ratio * coordinateB; + + m_impulse = 0.0f; +} + +void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_indexC = m_bodyC->m_islandIndex; + m_indexD = m_bodyD->m_islandIndex; + m_lcA = m_bodyA->m_sweep.localCenter; + m_lcB = m_bodyB->m_sweep.localCenter; + m_lcC = m_bodyC->m_sweep.localCenter; + m_lcD = m_bodyD->m_sweep.localCenter; + m_mA = m_bodyA->m_invMass; + m_mB = m_bodyB->m_invMass; + m_mC = m_bodyC->m_invMass; + m_mD = m_bodyD->m_invMass; + m_iA = m_bodyA->m_invI; + m_iB = m_bodyB->m_invI; + m_iC = m_bodyC->m_invI; + m_iD = m_bodyD->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + m_mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + m_JvAC.SetZero(); + m_JwA = 1.0f; + m_JwC = 1.0f; + m_mass += m_iA + m_iC; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + m_JvAC = u; + m_JwC = b2Cross(rC, u); + m_JwA = b2Cross(rA, u); + m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; + } + + if (m_typeB == e_revoluteJoint) + { + m_JvBD.SetZero(); + m_JwB = m_ratio; + m_JwD = m_ratio; + m_mass += m_ratio * m_ratio * (m_iB + m_iD); + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + m_JvBD = m_ratio * u; + m_JwD = m_ratio * b2Cross(rD, u); + m_JwB = m_ratio * b2Cross(rB, u); + m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; + } + + // Compute effective mass. + m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; + + if (data.step.warmStarting) + { + vA += (m_mA * m_impulse) * m_JvAC; + wA += m_iA * m_impulse * m_JwA; + vB += (m_mB * m_impulse) * m_JvBD; + wB += m_iB * m_impulse * m_JwB; + vC -= (m_mC * m_impulse) * m_JvAC; + wC -= m_iC * m_impulse * m_JwC; + vD -= (m_mD * m_impulse) * m_JvBD; + wD -= m_iD * m_impulse * m_JwD; + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); + Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); + + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + vA += (m_mA * impulse) * m_JvAC; + wA += m_iA * impulse * m_JwA; + vB += (m_mB * impulse) * m_JvBD; + wB += m_iB * impulse * m_JwB; + vC -= (m_mC * impulse) * m_JvAC; + wC -= m_iC * impulse * m_JwC; + vD -= (m_mD * impulse) * m_JvBD; + wD -= m_iD * impulse * m_JwD; + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + float32 linearError = 0.0f; + + float32 coordinateA, coordinateB; + + b2Vec2 JvAC, JvBD; + float32 JwA, JwB, JwC, JwD; + float32 mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + JvAC.SetZero(); + JwA = 1.0f; + JwC = 1.0f; + mass += m_iA + m_iC; + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + JvAC = u; + JwC = b2Cross(rC, u); + JwA = b2Cross(rA, u); + mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; + + b2Vec2 pC = m_localAnchorC - m_lcC; + b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + if (m_typeB == e_revoluteJoint) + { + JvBD.SetZero(); + JwB = m_ratio; + JwD = m_ratio; + mass += m_ratio * m_ratio * (m_iB + m_iD); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + JvBD = m_ratio * u; + JwD = m_ratio * b2Cross(rD, u); + JwB = m_ratio * b2Cross(rB, u); + mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; + + b2Vec2 pD = m_localAnchorD - m_lcD; + b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; + + float32 impulse = 0.0f; + if (mass > 0.0f) + { + impulse = -C / mass; + } + + cA += m_mA * impulse * JvAC; + aA += m_iA * impulse * JwA; + cB += m_mB * impulse * JvBD; + aB += m_iB * impulse * JwB; + cC -= m_mC * impulse * JvAC; + aC -= m_iC * impulse * JwC; + cD -= m_mD * impulse * JvBD; + aD -= m_iD * impulse * JwD; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + data.positions[m_indexC].c = cC; + data.positions[m_indexC].a = aC; + data.positions[m_indexD].c = cD; + data.positions[m_indexD].a = aD; + + // TODO_ERIN not implemented + return linearError < b2_linearSlop; +} + +b2Vec2 b2GearJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2GearJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_JvAC; + return inv_dt * P; +} + +float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const +{ + float32 L = m_impulse * m_JwA; + return inv_dt * L; +} + +void b2GearJoint::SetRatio(float32 ratio) +{ + b2Assert(b2IsValid(ratio)); + m_ratio = ratio; +} + +float32 b2GearJoint::GetRatio() const +{ + return m_ratio; +} + +void b2GearJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + int32 index1 = m_joint1->m_index; + int32 index2 = m_joint2->m_index; + + b2Log(" b2GearJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.joint1 = joints[%d];\n", index1); + b2Log(" jd.joint2 = joints[%d];\n", index2); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2GearJoint.h b/external/box2d/Dynamics/Joints/b2GearJoint.h new file mode 100644 index 0000000000..f926bf6ef1 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2GearJoint.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_GEAR_JOINT_H +#define B2_GEAR_JOINT_H + +#include + +/// Gear joint definition. This definition requires two existing +/// revolute or prismatic joints (any combination will work). +struct b2GearJointDef : public b2JointDef +{ + b2GearJointDef() + { + type = e_gearJoint; + joint1 = NULL; + joint2 = NULL; + ratio = 1.0f; + } + + /// The first revolute/prismatic joint attached to the gear joint. + b2Joint* joint1; + + /// The second revolute/prismatic joint attached to the gear joint. + b2Joint* joint2; + + /// The gear ratio. + /// @see b2GearJoint for explanation. + float32 ratio; +}; + +/// A gear joint is used to connect two joints together. Either joint +/// can be a revolute or prismatic joint. You specify a gear ratio +/// to bind the motions together: +/// coordinate1 + ratio * coordinate2 = constant +/// The ratio can be negative or positive. If one joint is a revolute joint +/// and the other joint is a prismatic joint, then the ratio will have units +/// of length or units of 1/length. +/// @warning You have to manually destroy the gear joint if joint1 or joint2 +/// is destroyed. +class b2GearJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first joint. + b2Joint* GetJoint1() { return m_joint1; } + + /// Get the second joint. + b2Joint* GetJoint2() { return m_joint2; } + + /// Set/Get the gear ratio. + void SetRatio(float32 ratio); + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2GearJoint(const b2GearJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Joint* m_joint1; + b2Joint* m_joint2; + + b2JointType m_typeA; + b2JointType m_typeB; + + // Body A is connected to body C + // Body B is connected to body D + b2Body* m_bodyC; + b2Body* m_bodyD; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localAnchorC; + b2Vec2 m_localAnchorD; + + b2Vec2 m_localAxisC; + b2Vec2 m_localAxisD; + + float32 m_referenceAngleA; + float32 m_referenceAngleB; + + float32 m_constant; + float32 m_ratio; + + float32 m_impulse; + + // Solver temp + int32 m_indexA, m_indexB, m_indexC, m_indexD; + b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; + float32 m_mA, m_mB, m_mC, m_mD; + float32 m_iA, m_iB, m_iC, m_iD; + b2Vec2 m_JvAC, m_JvBD; + float32 m_JwA, m_JwB, m_JwC, m_JwD; + float32 m_mass; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2Joint.cpp b/external/box2d/Dynamics/Joints/b2Joint.cpp new file mode 100644 index 0000000000..6853b09f0b --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2Joint.cpp @@ -0,0 +1,199 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) +{ + b2Joint* joint = NULL; + + switch (def->type) + { + case e_distanceJoint: + { + void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); + joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); + } + break; + + case e_mouseJoint: + { + void* mem = allocator->Allocate(sizeof(b2MouseJoint)); + joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); + } + break; + + case e_prismaticJoint: + { + void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); + joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); + } + break; + + case e_revoluteJoint: + { + void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); + joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); + } + break; + + case e_pulleyJoint: + { + void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); + joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); + } + break; + + case e_gearJoint: + { + void* mem = allocator->Allocate(sizeof(b2GearJoint)); + joint = new (mem) b2GearJoint((b2GearJointDef*)def); + } + break; + + case e_wheelJoint: + { + void* mem = allocator->Allocate(sizeof(b2WheelJoint)); + joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); + } + break; + + case e_weldJoint: + { + void* mem = allocator->Allocate(sizeof(b2WeldJoint)); + joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); + } + break; + + case e_frictionJoint: + { + void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); + joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); + } + break; + + case e_ropeJoint: + { + void* mem = allocator->Allocate(sizeof(b2RopeJoint)); + joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); + } + break; + + default: + b2Assert(false); + break; + } + + return joint; +} + +void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) +{ + joint->~b2Joint(); + switch (joint->m_type) + { + case e_distanceJoint: + allocator->Free(joint, sizeof(b2DistanceJoint)); + break; + + case e_mouseJoint: + allocator->Free(joint, sizeof(b2MouseJoint)); + break; + + case e_prismaticJoint: + allocator->Free(joint, sizeof(b2PrismaticJoint)); + break; + + case e_revoluteJoint: + allocator->Free(joint, sizeof(b2RevoluteJoint)); + break; + + case e_pulleyJoint: + allocator->Free(joint, sizeof(b2PulleyJoint)); + break; + + case e_gearJoint: + allocator->Free(joint, sizeof(b2GearJoint)); + break; + + case e_wheelJoint: + allocator->Free(joint, sizeof(b2WheelJoint)); + break; + + case e_weldJoint: + allocator->Free(joint, sizeof(b2WeldJoint)); + break; + + case e_frictionJoint: + allocator->Free(joint, sizeof(b2FrictionJoint)); + break; + + case e_ropeJoint: + allocator->Free(joint, sizeof(b2RopeJoint)); + break; + + default: + b2Assert(false); + break; + } +} + +b2Joint::b2Joint(const b2JointDef* def) +{ + b2Assert(def->bodyA != def->bodyB); + + m_type = def->type; + m_prev = NULL; + m_next = NULL; + m_bodyA = def->bodyA; + m_bodyB = def->bodyB; + m_index = 0; + m_collideConnected = def->collideConnected; + m_islandFlag = false; + m_userData = def->userData; + + m_edgeA.joint = NULL; + m_edgeA.other = NULL; + m_edgeA.prev = NULL; + m_edgeA.next = NULL; + + m_edgeB.joint = NULL; + m_edgeB.other = NULL; + m_edgeB.prev = NULL; + m_edgeB.next = NULL; +} + +bool b2Joint::IsActive() const +{ + return m_bodyA->IsActive() && m_bodyB->IsActive(); +} diff --git a/external/box2d/Dynamics/Joints/b2Joint.h b/external/box2d/Dynamics/Joints/b2Joint.h new file mode 100644 index 0000000000..b4ea576665 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2Joint.h @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_JOINT_H +#define B2_JOINT_H + +#include + +class b2Body; +class b2Joint; +struct b2SolverData; +class b2BlockAllocator; + +enum b2JointType +{ + e_unknownJoint, + e_revoluteJoint, + e_prismaticJoint, + e_distanceJoint, + e_pulleyJoint, + e_mouseJoint, + e_gearJoint, + e_wheelJoint, + e_weldJoint, + e_frictionJoint, + e_ropeJoint +}; + +enum b2LimitState +{ + e_inactiveLimit, + e_atLowerLimit, + e_atUpperLimit, + e_equalLimits +}; + +struct b2Jacobian +{ + b2Vec2 linear; + float32 angularA; + float32 angularB; +}; + +/// A joint edge is used to connect bodies and joints together +/// in a joint graph where each body is a node and each joint +/// is an edge. A joint edge belongs to a doubly linked list +/// maintained in each attached body. Each joint has two joint +/// nodes, one for each attached body. +struct b2JointEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Joint* joint; ///< the joint + b2JointEdge* prev; ///< the previous joint edge in the body's joint list + b2JointEdge* next; ///< the next joint edge in the body's joint list +}; + +/// Joint definitions are used to construct joints. +struct b2JointDef +{ + b2JointDef() + { + type = e_unknownJoint; + userData = NULL; + bodyA = NULL; + bodyB = NULL; + collideConnected = false; + } + + /// The joint type is set automatically for concrete joint types. + b2JointType type; + + /// Use this to attach application specific data to your joints. + void* userData; + + /// The first attached body. + b2Body* bodyA; + + /// The second attached body. + b2Body* bodyB; + + /// Set this flag to true if the attached bodies should collide. + bool collideConnected; +}; + +/// The base joint class. Joints are used to constraint two bodies together in +/// various fashions. Some joints also feature limits and motors. +class b2Joint +{ +public: + + /// Get the type of the concrete joint. + b2JointType GetType() const; + + /// Get the first body attached to this joint. + b2Body* GetBodyA(); + + /// Get the second body attached to this joint. + b2Body* GetBodyB(); + + /// Get the anchor point on bodyA in world coordinates. + virtual b2Vec2 GetAnchorA() const = 0; + + /// Get the anchor point on bodyB in world coordinates. + virtual b2Vec2 GetAnchorB() const = 0; + + /// Get the reaction force on bodyB at the joint anchor in Newtons. + virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; + + /// Get the reaction torque on bodyB in N*m. + virtual float32 GetReactionTorque(float32 inv_dt) const = 0; + + /// Get the next joint the world joint list. + b2Joint* GetNext(); + const b2Joint* GetNext() const; + + /// Get the user data pointer. + void* GetUserData() const; + + /// Set the user data pointer. + void SetUserData(void* data); + + /// Short-cut function to determine if either body is inactive. + bool IsActive() const; + + /// Get collide connected. + /// Note: modifying the collide connect flag won't work correctly because + /// the flag is only checked when fixture AABBs begin to overlap. + bool GetCollideConnected() const; + + /// Dump this joint to the log file. + virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } + +protected: + friend class b2World; + friend class b2Body; + friend class b2Island; + friend class b2GearJoint; + + static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); + static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); + + b2Joint(const b2JointDef* def); + virtual ~b2Joint() {} + + virtual void InitVelocityConstraints(const b2SolverData& data) = 0; + virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; + + // This returns true if the position errors are within tolerance. + virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; + + b2JointType m_type; + b2Joint* m_prev; + b2Joint* m_next; + b2JointEdge m_edgeA; + b2JointEdge m_edgeB; + b2Body* m_bodyA; + b2Body* m_bodyB; + + int32 m_index; + + bool m_islandFlag; + bool m_collideConnected; + + void* m_userData; +}; + +inline b2JointType b2Joint::GetType() const +{ + return m_type; +} + +inline b2Body* b2Joint::GetBodyA() +{ + return m_bodyA; +} + +inline b2Body* b2Joint::GetBodyB() +{ + return m_bodyB; +} + +inline b2Joint* b2Joint::GetNext() +{ + return m_next; +} + +inline const b2Joint* b2Joint::GetNext() const +{ + return m_next; +} + +inline void* b2Joint::GetUserData() const +{ + return m_userData; +} + +inline void b2Joint::SetUserData(void* data) +{ + m_userData = data; +} + +inline bool b2Joint::GetCollideConnected() const +{ + return m_collideConnected; +} + +#endif diff --git a/external/box2d/Dynamics/Joints/b2MouseJoint.cpp b/external/box2d/Dynamics/Joints/b2MouseJoint.cpp new file mode 100644 index 0000000000..237d9d519a --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2MouseJoint.cpp @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include + +// p = attached point, m = mouse point +// C = p - m +// Cdot = v +// = v + cross(w, r) +// J = [I r_skew] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) +: b2Joint(def) +{ + b2Assert(def->target.IsValid()); + b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); + b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); + b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); + + m_targetA = def->target; + m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); + + m_maxForce = def->maxForce; + m_impulse.SetZero(); + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_beta = 0.0f; + m_gamma = 0.0f; +} + +void b2MouseJoint::SetTarget(const b2Vec2& target) +{ + if (m_bodyB->IsAwake() == false) + { + m_bodyB->SetAwake(true); + } + m_targetA = target; +} + +const b2Vec2& b2MouseJoint::GetTarget() const +{ + return m_targetA; +} + +void b2MouseJoint::SetMaxForce(float32 force) +{ + m_maxForce = force; +} + +float32 b2MouseJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2MouseJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +float32 b2MouseJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +void b2MouseJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +float32 b2MouseJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexB = m_bodyB->m_islandIndex; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassB = m_bodyB->m_invMass; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qB(aB); + + float32 mass = m_bodyB->GetMass(); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = mass * (omega * omega); + + // magic formulas + // gamma has units of inverse mass. + // beta has units of inverse time. + float32 h = data.step.dt; + b2Assert(d + h * k > b2_epsilon); + m_gamma = h * (d + h * k); + if (m_gamma != 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + m_beta = h * k * m_gamma; + + // Compute the effective mass matrix. + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] + // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] + // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] + b2Mat22 K; + K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; + K.ex.y = -m_invIB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; + + m_mass = K.GetInverse(); + + m_C = cB + m_rB - m_targetA; + m_C *= m_beta; + + // Cheat with some damping + wB *= 0.98f; + + if (data.step.warmStarting) + { + m_impulse *= data.step.dtRatio; + vB += m_invMassB * m_impulse; + wB += m_invIB * b2Cross(m_rB, m_impulse); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = v + cross(w, r) + b2Vec2 Cdot = vB + b2Cross(wB, m_rB); + b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); + + b2Vec2 oldImpulse = m_impulse; + m_impulse += impulse; + float32 maxImpulse = data.step.dt * m_maxForce; + if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_impulse *= maxImpulse / m_impulse.Length(); + } + impulse = m_impulse - oldImpulse; + + vB += m_invMassB * impulse; + wB += m_invIB * b2Cross(m_rB, impulse); + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + return true; +} + +b2Vec2 b2MouseJoint::GetAnchorA() const +{ + return m_targetA; +} + +b2Vec2 b2MouseJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_impulse; +} + +float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * 0.0f; +} diff --git a/external/box2d/Dynamics/Joints/b2MouseJoint.h b/external/box2d/Dynamics/Joints/b2MouseJoint.h new file mode 100644 index 0000000000..1bbc194f4c --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2MouseJoint.h @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_MOUSE_JOINT_H +#define B2_MOUSE_JOINT_H + +#include + +/// Mouse joint definition. This requires a world target point, +/// tuning parameters, and the time step. +struct b2MouseJointDef : public b2JointDef +{ + b2MouseJointDef() + { + type = e_mouseJoint; + target.Set(0.0f, 0.0f); + maxForce = 0.0f; + frequencyHz = 5.0f; + dampingRatio = 0.7f; + } + + /// The initial world target point. This is assumed + /// to coincide with the body anchor initially. + b2Vec2 target; + + /// The maximum constraint force that can be exerted + /// to move the candidate body. Usually you will express + /// as some multiple of the weight (multiplier * mass * gravity). + float32 maxForce; + + /// The response speed. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A mouse joint is used to make a point on a body track a +/// specified world point. This a soft constraint with a maximum +/// force. This allows the constraint to stretch and without +/// applying huge forces. +/// NOTE: this joint is not documented in the manual because it was +/// developed to be used in the testbed. If you want to learn how to +/// use the mouse joint, look at the testbed. +class b2MouseJoint : public b2Joint +{ +public: + + /// Implements b2Joint. + b2Vec2 GetAnchorA() const; + + /// Implements b2Joint. + b2Vec2 GetAnchorB() const; + + /// Implements b2Joint. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Implements b2Joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Use this to update the target point. + void SetTarget(const b2Vec2& target); + const b2Vec2& GetTarget() const; + + /// Set/get the maximum force in Newtons. + void SetMaxForce(float32 force); + float32 GetMaxForce() const; + + /// Set/get the frequency in Hertz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get the damping ratio (dimensionless). + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// The mouse joint does not support dumping. + void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } + +protected: + friend class b2Joint; + + b2MouseJoint(const b2MouseJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorB; + b2Vec2 m_targetA; + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_beta; + + // Solver shared + b2Vec2 m_impulse; + float32 m_maxForce; + float32 m_gamma; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rB; + b2Vec2 m_localCenterB; + float32 m_invMassB; + float32 m_invIB; + b2Mat22 m_mass; + b2Vec2 m_C; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp b/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp new file mode 100644 index 0000000000..4849f729f5 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp @@ -0,0 +1,637 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Linear constraint (point-to-line) +// d = p2 - p1 = x2 + r2 - x1 - r1 +// C = dot(perp, d) +// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) +// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] +// +// Angular constraint +// C = a2 - a1 + a_initial +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// +// K = J * invM * JT +// +// J = [-a -s1 a s2] +// [0 -1 0 1] +// a = perp +// s1 = cross(d + r1, a) = cross(p2 - x1, a) +// s2 = cross(r2, a) = cross(p2 - x2, a) + + +// Motor/Limit linear constraint +// C = dot(ax1, d) +// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) +// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] + +// Block Solver +// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even +// when the mass has poor distribution (leading to large torques about the joint anchor points). +// +// The Jacobian has 3 rows: +// J = [-uT -s1 uT s2] // linear +// [0 -1 0 1] // angular +// [-vT -a1 vT a2] // limit +// +// u = perp +// v = axis +// s1 = cross(d + r1, u), s2 = cross(r2, u) +// a1 = cross(d + r1, v), a2 = cross(r2, v) + +// M * (v2 - v1) = JT * df +// J * v2 = bias +// +// v2 = v1 + invM * JT * df +// J * (v1 + invM * JT * df) = bias +// K * df = bias - J * v1 = -Cdot +// K = J * invM * JT +// Cdot = J * v1 - bias +// +// Now solve for f2. +// df = f2 - f1 +// K * (f2 - f1) = -Cdot +// f2 = invK * (-Cdot) + f1 +// +// Clamp accumulated limit impulse. +// lower: f2(3) = max(f2(3), 0) +// upper: f2(3) = min(f2(3), 0) +// +// Solve for correct f2(1:2) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 +// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) +// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) +// +// Now compute impulse to be applied: +// df = f2 - f1 + +void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localXAxisA.Normalize(); + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + + m_lowerTranslation = def->lowerTranslation; + m_upperTranslation = def->upperTranslation; + m_maxMotorForce = def->maxMotorForce; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; + + m_axis.SetZero(); + m_perp.SetZero(); +} + +void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute motor Jacobian and effective mass. + { + m_axis = b2Mul(qA, m_localXAxisA); + m_a1 = b2Cross(d + rA, m_axis); + m_a2 = b2Cross(rB, m_axis); + + m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + + // Prismatic constraint. + { + m_perp = b2Mul(qA, m_localYAxisA); + + m_s1 = b2Cross(d + rA, m_perp); + m_s2 = b2Cross(rB, m_perp); + + float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; + float32 k12 = iA * m_s1 + iB * m_s2; + float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For bodies with fixed rotation. + k22 = 1.0f; + } + float32 k23 = iA * m_a1 + iB * m_a2; + float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + + m_K.ex.Set(k11, k12, k13); + m_K.ey.Set(k12, k22, k23); + m_K.ez.Set(k13, k23, k33); + } + + // Compute motor and limit terms. + if (m_enableLimit) + { + float32 jointTranslation = b2Dot(m_axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + m_limitState = e_equalLimits; + } + else if (jointTranslation <= m_lowerTranslation) + { + if (m_limitState != e_atLowerLimit) + { + m_limitState = e_atLowerLimit; + m_impulse.z = 0.0f; + } + } + else if (jointTranslation >= m_upperTranslation) + { + if (m_limitState != e_atUpperLimit) + { + m_limitState = e_atUpperLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + + if (m_enableMotor == false) + { + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; + float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; + float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Solve linear motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits) + { + float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + float32 impulse = m_motorMass * (m_motorSpeed - Cdot); + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorForce; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + b2Vec2 P = impulse * m_axis; + float32 LA = impulse * m_a1; + float32 LB = impulse * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + b2Vec2 Cdot1; + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (m_enableLimit && m_limitState != e_inactiveLimit) + { + // Solve prismatic and limit constraint in block form. + float32 Cdot2; + Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 f1 = m_impulse; + b2Vec3 df = m_K.Solve33(-Cdot); + m_impulse += df; + + if (m_limitState == e_atLowerLimit) + { + m_impulse.z = b2Max(m_impulse.z, 0.0f); + } + else if (m_limitState == e_atUpperLimit) + { + m_impulse.z = b2Min(m_impulse.z, 0.0f); + } + + // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) + b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); + b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); + m_impulse.x = f2r.x; + m_impulse.y = f2r.y; + + df = m_impulse - f1; + + b2Vec2 P = df.x * m_perp + df.z * m_axis; + float32 LA = df.x * m_s1 + df.y + df.z * m_a1; + float32 LB = df.x * m_s2 + df.y + df.z * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + // Limit is inactive, just solve the prismatic constraint in block form. + b2Vec2 df = m_K.Solve22(-Cdot1); + m_impulse.x += df.x; + m_impulse.y += df.y; + + b2Vec2 P = df.x * m_perp; + float32 LA = df.x * m_s1 + df.y; + float32 LB = df.x * m_s2 + df.y; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + + b2Vec2 Cdot10 = Cdot1; + + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f) + { + b2Vec2 test = b2Mul22(m_K, df); + Cdot1.x += 0.0f; + } + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute fresh Jacobians + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + b2Vec2 axis = b2Mul(qA, m_localXAxisA); + float32 a1 = b2Cross(d + rA, axis); + float32 a2 = b2Cross(rB, axis); + b2Vec2 perp = b2Mul(qA, m_localYAxisA); + + float32 s1 = b2Cross(d + rA, perp); + float32 s2 = b2Cross(rB, perp); + + b2Vec3 impulse; + b2Vec2 C1; + C1.x = b2Dot(perp, d); + C1.y = aB - aA - m_referenceAngle; + + float32 linearError = b2Abs(C1.x); + float32 angularError = b2Abs(C1.y); + + bool active = false; + float32 C2 = 0.0f; + if (m_enableLimit) + { + float32 translation = b2Dot(axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + // Prevent large angular corrections + C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); + linearError = b2Max(linearError, b2Abs(translation)); + active = true; + } + else if (translation <= m_lowerTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); + linearError = b2Max(linearError, m_lowerTranslation - translation); + active = true; + } + else if (translation >= m_upperTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); + linearError = b2Max(linearError, translation - m_upperTranslation); + active = true; + } + } + + if (active) + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k13 = iA * s1 * a1 + iB * s2 * a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For fixed rotation + k22 = 1.0f; + } + float32 k23 = iA * a1 + iB * a2; + float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; + + b2Mat33 K; + K.ex.Set(k11, k12, k13); + K.ey.Set(k12, k22, k23); + K.ez.Set(k13, k23, k33); + + b2Vec3 C; + C.x = C1.x; + C.y = C1.y; + C.z = C2; + + impulse = K.Solve33(-C); + } + else + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + k22 = 1.0f; + } + + b2Mat22 K; + K.ex.Set(k11, k12); + K.ey.Set(k12, k22); + + b2Vec2 impulse1 = K.Solve(-C1); + impulse.x = impulse1.x; + impulse.y = impulse1.y; + impulse.z = 0.0f; + } + + b2Vec2 P = impulse.x * perp + impulse.z * axis; + float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; + float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; + + cA -= mA * P; + aA -= iA * LA; + cB += mB * P; + aB += iB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2PrismaticJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PrismaticJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); +} + +float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.y; +} + +float32 b2PrismaticJoint::GetJointTranslation() const +{ + b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2PrismaticJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); + b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); + b2Vec2 p1 = bA->m_sweep.c + rA; + b2Vec2 p2 = bB->m_sweep.c + rB; + b2Vec2 d = p2 - p1; + b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); + + b2Vec2 vA = bA->m_linearVelocity; + b2Vec2 vB = bB->m_linearVelocity; + float32 wA = bA->m_angularVelocity; + float32 wB = bB->m_angularVelocity; + + float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); + return speed; +} + +bool b2PrismaticJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2PrismaticJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2PrismaticJoint::GetLowerLimit() const +{ + return m_lowerTranslation; +} + +float32 b2PrismaticJoint::GetUpperLimit() const +{ + return m_upperTranslation; +} + +void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + if (lower != m_lowerTranslation || upper != m_upperTranslation) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_lowerTranslation = lower; + m_upperTranslation = upper; + m_impulse.z = 0.0f; + } +} + +bool b2PrismaticJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2PrismaticJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2PrismaticJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2PrismaticJoint::SetMaxMotorForce(float32 force) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorForce = force; +} + +float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2PrismaticJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PrismaticJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); + b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2PrismaticJoint.h b/external/box2d/Dynamics/Joints/b2PrismaticJoint.h new file mode 100644 index 0000000000..aca2859b45 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2PrismaticJoint.h @@ -0,0 +1,196 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_PRISMATIC_JOINT_H +#define B2_PRISMATIC_JOINT_H + +#include + +/// Prismatic joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct b2PrismaticJointDef : public b2JointDef +{ + b2PrismaticJointDef() + { + type = e_prismaticJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + referenceAngle = 0.0f; + enableLimit = false; + lowerTranslation = 0.0f; + upperTranslation = 0.0f; + enableMotor = false; + maxMotorForce = 0.0f; + motorSpeed = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and unit world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA. + b2Vec2 localAxisA; + + /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. + float32 referenceAngle; + + /// Enable/disable the joint limit. + bool enableLimit; + + /// The lower translation limit, usually in meters. + float32 lowerTranslation; + + /// The upper translation limit, usually in meters. + float32 upperTranslation; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorForce; + + /// The desired motor speed in radians per second. + float32 motorSpeed; +}; + +/// A prismatic joint. This joint provides one degree of freedom: translation +/// along an axis fixed in bodyA. Relative rotation is prevented. You can +/// use a joint limit to restrict the range of motion and a joint motor to +/// drive the motion or to model joint friction. +class b2PrismaticJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit, usually in meters. + float32 GetLowerLimit() const; + + /// Get the upper joint limit, usually in meters. + float32 GetUpperLimit() const; + + /// Set the joint limits, usually in meters. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in meters per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in meters per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor force, usually in N. + void SetMaxMotorForce(float32 force); + float32 GetMaxMotorForce() const { return m_maxMotorForce; } + + /// Get the current motor force given the inverse time step, usually in N. + float32 GetMotorForce(float32 inv_dt) const; + + /// Dump to b2Log + void Dump(); + +protected: + friend class b2Joint; + friend class b2GearJoint; + b2PrismaticJoint(const b2PrismaticJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + float32 m_referenceAngle; + b2Vec3 m_impulse; + float32 m_motorImpulse; + float32 m_lowerTranslation; + float32 m_upperTranslation; + float32 m_maxMotorForce; + float32 m_motorSpeed; + bool m_enableLimit; + bool m_enableMotor; + b2LimitState m_limitState; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Vec2 m_axis, m_perp; + float32 m_s1, m_s2; + float32 m_a1, m_a2; + b2Mat33 m_K; + float32 m_motorMass; +}; + +inline float32 b2PrismaticJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp b/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp new file mode 100644 index 0000000000..da30fae222 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp @@ -0,0 +1,332 @@ +/* +* Copyright (c) 2007 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 +#include +#include + +// Pulley: +// length1 = norm(p1 - s1) +// length2 = norm(p2 - s2) +// C0 = (length1 + ratio * length2)_initial +// C = C0 - (length1 + ratio * length2) +// u1 = (p1 - s1) / norm(p1 - s1) +// u2 = (p2 - s2) / norm(p2 - s2) +// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) +// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) + +void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, + const b2Vec2& groundA, const b2Vec2& groundB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 r) +{ + bodyA = bA; + bodyB = bB; + groundAnchorA = groundA; + groundAnchorB = groundB; + localAnchorA = bodyA->GetLocalPoint(anchorA); + localAnchorB = bodyB->GetLocalPoint(anchorB); + b2Vec2 dA = anchorA - groundA; + lengthA = dA.Length(); + b2Vec2 dB = anchorB - groundB; + lengthB = dB.Length(); + ratio = r; + b2Assert(ratio > b2_epsilon); +} + +b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) +: b2Joint(def) +{ + m_groundAnchorA = def->groundAnchorA; + m_groundAnchorB = def->groundAnchorB; + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_lengthA = def->lengthA; + m_lengthB = def->lengthB; + + b2Assert(def->ratio != 0.0f); + m_ratio = def->ratio; + + m_constant = def->lengthA + m_ratio * def->lengthB; + + m_impulse = 0.0f; +} + +void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + m_uA = cA + m_rA - m_groundAnchorA; + m_uB = cB + m_rB - m_groundAnchorB; + + float32 lengthA = m_uA.Length(); + float32 lengthB = m_uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + m_uA *= 1.0f / lengthA; + } + else + { + m_uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + m_uB *= 1.0f / lengthB; + } + else + { + m_uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(m_rA, m_uA); + float32 ruB = b2Cross(m_rB, m_uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + m_mass = mA + m_ratio * m_ratio * mB; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support variable time steps. + m_impulse *= data.step.dtRatio; + + // Warm starting. + b2Vec2 PA = -(m_impulse) * m_uA; + b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; + + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + + float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 PA = -impulse * m_uA; + b2Vec2 PB = -m_ratio * impulse * m_uB; + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + b2Vec2 uA = cA + rA - m_groundAnchorA; + b2Vec2 uB = cB + rB - m_groundAnchorB; + + float32 lengthA = uA.Length(); + float32 lengthB = uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + uA *= 1.0f / lengthA; + } + else + { + uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + uB *= 1.0f / lengthB; + } + else + { + uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(rA, uA); + float32 ruB = b2Cross(rB, uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + float32 mass = mA + m_ratio * m_ratio * mB; + + if (mass > 0.0f) + { + mass = 1.0f / mass; + } + + float32 C = m_constant - lengthA - m_ratio * lengthB; + float32 linearError = b2Abs(C); + + float32 impulse = -mass * C; + + b2Vec2 PA = -impulse * uA; + b2Vec2 PB = -m_ratio * impulse * uB; + + cA += m_invMassA * PA; + aA += m_invIA * b2Cross(rA, PA); + cB += m_invMassB * PB; + aB += m_invIB * b2Cross(rB, PB); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError < b2_linearSlop; +} + +b2Vec2 b2PulleyJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PulleyJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_uB; + return inv_dt * P; +} + +float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorA() const +{ + return m_groundAnchorA; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorB() const +{ + return m_groundAnchorB; +} + +float32 b2PulleyJoint::GetLengthA() const +{ + b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 s = m_groundAnchorA; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetLengthB() const +{ + b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 s = m_groundAnchorB; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetRatio() const +{ + return m_ratio; +} + +void b2PulleyJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PulleyJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); + b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); + b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2PulleyJoint.h b/external/box2d/Dynamics/Joints/b2PulleyJoint.h new file mode 100644 index 0000000000..2f6df4395c --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2PulleyJoint.h @@ -0,0 +1,143 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_PULLEY_JOINT_H +#define B2_PULLEY_JOINT_H + +#include + +const float32 b2_minPulleyLength = 2.0f; + +/// Pulley joint definition. This requires two ground anchors, +/// two dynamic body anchor points, and a pulley ratio. +struct b2PulleyJointDef : public b2JointDef +{ + b2PulleyJointDef() + { + type = e_pulleyJoint; + groundAnchorA.Set(-1.0f, 1.0f); + groundAnchorB.Set(1.0f, 1.0f); + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + lengthA = 0.0f; + lengthB = 0.0f; + ratio = 1.0f; + collideConnected = true; + } + + /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 ratio); + + /// The first ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorA; + + /// The second ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorB; + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The a reference length for the segment attached to bodyA. + float32 lengthA; + + /// The a reference length for the segment attached to bodyB. + float32 lengthB; + + /// The pulley ratio, used to simulate a block-and-tackle. + float32 ratio; +}; + +/// The pulley joint is connected to two bodies and two fixed ground points. +/// The pulley supports a ratio such that: +/// length1 + ratio * length2 <= constant +/// Yes, the force transmitted is scaled by the ratio. +/// Warning: the pulley joint can get a bit squirrelly by itself. They often +/// work better when combined with prismatic joints. You should also cover the +/// the anchor points with static shapes to prevent one side from going to +/// zero length. +class b2PulleyJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first ground anchor. + b2Vec2 GetGroundAnchorA() const; + + /// Get the second ground anchor. + b2Vec2 GetGroundAnchorB() const; + + /// Get the current length of the segment attached to bodyA. + float32 GetLengthA() const; + + /// Get the current length of the segment attached to bodyB. + float32 GetLengthB() const; + + /// Get the pulley ratio. + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2PulleyJoint(const b2PulleyJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_groundAnchorA; + b2Vec2 m_groundAnchorB; + float32 m_lengthA; + float32 m_lengthB; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_constant; + float32 m_ratio; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_uA; + b2Vec2 m_uB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp b/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp new file mode 100644 index 0000000000..e265d8192b --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp @@ -0,0 +1,504 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Motor constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + + m_lowerAngle = def->lowerAngle; + m_upperAngle = def->upperAngle; + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; +} + +void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; + m_mass.ex.y = m_mass.ey.x; + m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; + m_mass.ex.z = m_mass.ez.x; + m_mass.ey.z = m_mass.ez.y; + m_mass.ez.z = iA + iB; + + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + + if (m_enableMotor == false || fixedRotation) + { + m_motorImpulse = 0.0f; + } + + if (m_enableLimit && fixedRotation == false) + { + float32 jointAngle = aB - aA - m_referenceAngle; + if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) + { + m_limitState = e_equalLimits; + } + else if (jointAngle <= m_lowerAngle) + { + if (m_limitState != e_atLowerLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atLowerLimit; + } + else if (jointAngle >= m_upperAngle) + { + if (m_limitState != e_atUpperLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atUpperLimit; + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + // Solve motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -m_mass.Solve33(Cdot); + + if (m_limitState == e_equalLimits) + { + m_impulse += impulse; + } + else if (m_limitState == e_atLowerLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse < 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + else if (m_limitState == e_atUpperLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse > 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + else + { + // Solve point-to-point constraint + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + b2Vec2 impulse = m_mass.Solve22(-Cdot); + + m_impulse.x += impulse.x; + m_impulse.y += impulse.y; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 angularError = 0.0f; + float32 positionError = 0.0f; + + bool fixedRotation = (m_invIA + m_invIB == 0.0f); + + // Solve angular limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + float32 angle = aB - aA - m_referenceAngle; + float32 limitImpulse = 0.0f; + + if (m_limitState == e_equalLimits) + { + // Prevent large angular corrections + float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + angularError = b2Abs(C); + } + else if (m_limitState == e_atLowerLimit) + { + float32 C = angle - m_lowerAngle; + angularError = -C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); + limitImpulse = -m_motorMass * C; + } + else if (m_limitState == e_atUpperLimit) + { + float32 C = angle - m_upperAngle; + angularError = C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + } + + aA -= m_invIA * limitImpulse; + aB += m_invIB * limitImpulse; + } + + // Solve point-to-point constraint. + { + qA.Set(aA); + qB.Set(aB); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + b2Vec2 C = cB + rB - cA - rA; + positionError = C.Length(); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; + K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; + + b2Vec2 impulse = -K.Solve(C); + + cA -= mA * impulse; + aA -= iA * b2Cross(rA, impulse); + + cB += mB * impulse; + aB += iB * b2Cross(rB, impulse); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2RevoluteJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RevoluteJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +float32 b2RevoluteJoint::GetJointAngle() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; +} + +float32 b2RevoluteJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_angularVelocity - bA->m_angularVelocity; +} + +bool b2RevoluteJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2RevoluteJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2RevoluteJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +bool b2RevoluteJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2RevoluteJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2RevoluteJoint::GetLowerLimit() const +{ + return m_lowerAngle; +} + +float32 b2RevoluteJoint::GetUpperLimit() const +{ + return m_upperAngle; +} + +void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + + if (lower != m_lowerAngle || upper != m_upperAngle) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_impulse.z = 0.0f; + m_lowerAngle = lower; + m_upperAngle = upper; + } +} + +void b2RevoluteJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RevoluteJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); + b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2RevoluteJoint.h b/external/box2d/Dynamics/Joints/b2RevoluteJoint.h new file mode 100644 index 0000000000..978f16259a --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2RevoluteJoint.h @@ -0,0 +1,204 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_REVOLUTE_JOINT_H +#define B2_REVOLUTE_JOINT_H + +#include + +/// Revolute joint definition. This requires defining an +/// anchor point where the bodies are joined. The definition +/// uses local anchor points so that the initial configuration +/// can violate the constraint slightly. You also need to +/// specify the initial relative angle for joint limits. This +/// helps when saving and loading a game. +/// The local anchor points are measured from the body's origin +/// rather than the center of mass because: +/// 1. you might not know where the center of mass will be. +/// 2. if you add/remove shapes from a body and recompute the mass, +/// the joints will be broken. +struct b2RevoluteJointDef : public b2JointDef +{ + b2RevoluteJointDef() + { + type = e_revoluteJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + lowerAngle = 0.0f; + upperAngle = 0.0f; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + enableLimit = false; + enableMotor = false; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// A flag to enable joint limits. + bool enableLimit; + + /// The lower angle for the joint limit (radians). + float32 lowerAngle; + + /// The upper angle for the joint limit (radians). + float32 upperAngle; + + /// A flag to enable the joint motor. + bool enableMotor; + + /// The desired motor speed. Usually in radians per second. + float32 motorSpeed; + + /// The maximum motor torque used to achieve the desired motor speed. + /// Usually in N-m. + float32 maxMotorTorque; +}; + +/// A revolute joint constrains two bodies to share a common point while they +/// are free to rotate about the point. The relative rotation about the shared +/// point is the joint angle. You can limit the relative rotation with +/// a joint limit that specifies a lower and upper angle. You can use a motor +/// to drive the relative rotation about the shared point. A maximum motor torque +/// is provided so that infinite forces are not generated. +class b2RevoluteJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint angle in radians. + float32 GetJointAngle() const; + + /// Get the current joint angle speed in radians per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit in radians. + float32 GetLowerLimit() const; + + /// Get the upper joint limit in radians. + float32 GetUpperLimit() const; + + /// Set the joint limits in radians. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed in radians per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor torque, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque due to the joint limit given the inverse time step. + /// Unit is N*m. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the current motor torque given the inverse time step. + /// Unit is N*m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Dump to b2Log. + void Dump(); + +protected: + + friend class b2Joint; + friend class b2GearJoint; + + b2RevoluteJoint(const b2RevoluteJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec3 m_impulse; + float32 m_motorImpulse; + + bool m_enableMotor; + float32 m_maxMotorTorque; + float32 m_motorSpeed; + + bool m_enableLimit; + float32 m_referenceAngle; + float32 m_lowerAngle; + float32 m_upperAngle; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; // effective mass for point-to-point constraint. + float32 m_motorMass; // effective mass for motor/limit angular constraint. + b2LimitState m_limitState; +}; + +inline float32 b2RevoluteJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/external/box2d/Dynamics/Joints/b2RopeJoint.cpp b/external/box2d/Dynamics/Joints/b2RopeJoint.cpp new file mode 100644 index 0000000000..17a70d9230 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2RopeJoint.cpp @@ -0,0 +1,241 @@ +/* +* Copyright (c) 2007-2011 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 +#include +#include + + +// Limit: +// C = norm(pB - pA) - L +// u = (pB - pA) / norm(pB - pA) +// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) +// J = [-u -cross(rA, u) u cross(rB, u)] +// K = J * invM * JT +// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 + +b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_maxLength = def->maxLength; + + m_mass = 0.0f; + m_impulse = 0.0f; + m_state = e_inactiveLimit; + m_length = 0.0f; +} + +void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + m_length = m_u.Length(); + + float32 C = m_length - m_maxLength; + if (C > 0.0f) + { + m_state = e_atUpperLimit; + } + else + { + m_state = e_inactiveLimit; + } + + if (m_length > b2_linearSlop) + { + m_u *= 1.0f / m_length; + } + else + { + m_u.SetZero(); + m_mass = 0.0f; + m_impulse = 0.0f; + return; + } + + // Compute effective mass. + float32 crA = b2Cross(m_rA, m_u); + float32 crB = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; + + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 C = m_length - m_maxLength; + float32 Cdot = b2Dot(m_u, vpB - vpA); + + // Predictive constraint. + if (C < 0.0f) + { + Cdot += data.step.inv_dt * C; + } + + float32 impulse = -m_mass * Cdot; + float32 oldImpulse = m_impulse; + m_impulse = b2Min(0.0f, m_impulse + impulse); + impulse = m_impulse - oldImpulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_maxLength; + + C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return length - m_maxLength < b2_linearSlop; +} + +b2Vec2 b2RopeJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RopeJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +float32 b2RopeJoint::GetMaxLength() const +{ + return m_maxLength; +} + +b2LimitState b2RopeJoint::GetLimitState() const +{ + return m_state; +} + +void b2RopeJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RopeJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2RopeJoint.h b/external/box2d/Dynamics/Joints/b2RopeJoint.h new file mode 100644 index 0000000000..d7091b6650 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2RopeJoint.h @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_ROPE_JOINT_H +#define B2_ROPE_JOINT_H + +#include + +/// Rope joint definition. This requires two body anchor points and +/// a maximum lengths. +/// Note: by default the connected objects will not collide. +/// see collideConnected in b2JointDef. +struct b2RopeJointDef : public b2JointDef +{ + b2RopeJointDef() + { + type = e_ropeJoint; + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + maxLength = 0.0f; + } + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum length of the rope. + /// Warning: this must be larger than b2_linearSlop or + /// the joint will have no effect. + float32 maxLength; +}; + +/// A rope joint enforces a maximum distance between two points +/// on two bodies. It has no other effect. +/// Warning: if you attempt to change the maximum length during +/// the simulation you will get some non-physical behavior. +/// A model that would allow you to dynamically modify the length +/// would have some sponginess, so I chose not to implement it +/// that way. See b2DistanceJoint if you want to dynamically +/// control length. +class b2RopeJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/Get the maximum length of the rope. + void SetMaxLength(float32 length) { m_maxLength = length; } + float32 GetMaxLength() const; + + b2LimitState GetLimitState() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2RopeJoint(const b2RopeJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_maxLength; + float32 m_length; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; + b2LimitState m_state; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2WeldJoint.cpp b/external/box2d/Dynamics/Joints/b2WeldJoint.cpp new file mode 100644 index 0000000000..f50bdd6587 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2WeldJoint.cpp @@ -0,0 +1,330 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// C = angle2 - angle1 - referenceAngle +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_impulse.SetZero(); +} + +void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat33 K; + K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + K.ez.x = -m_rA.y * iA - m_rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + K.ez.y = m_rA.x * iA + m_rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + K.GetInverse22(&m_mass); + + float32 invM = iA + iB; + float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; + + float32 C = aB - aA - m_referenceAngle; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invM += m_gamma; + m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; + } + else + { + K.GetSymInverse33(&m_mass); + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_impulse.z); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + if (m_frequencyHz > 0.0f) + { + float32 Cdot2 = wB - wA; + + float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); + m_impulse.z += impulse2; + + wA -= iA * impulse2; + wB += iB * impulse2; + + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); + m_impulse.x += impulse1.x; + m_impulse.y += impulse1.y; + + b2Vec2 P = impulse1; + + vA -= mA * P; + wA -= iA * b2Cross(m_rA, P); + + vB += mB * P; + wB += iB * b2Cross(m_rB, P); + } + else + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -b2Mul(m_mass, Cdot); + m_impulse += impulse; + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + float32 positionError, angularError; + + b2Mat33 K; + K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; + K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; + K.ez.x = -rA.y * iA - rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; + K.ez.y = rA.x * iA + rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + b2Vec2 C1 = cB + rB - cA - rA; + + positionError = C1.Length(); + angularError = 0.0f; + + b2Vec2 P = -K.Solve22(C1); + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + else + { + b2Vec2 C1 = cB + rB - cA - rA; + float32 C2 = aB - aA - m_referenceAngle; + + positionError = C1.Length(); + angularError = b2Abs(C2); + + b2Vec3 C(C1.x, C1.y, C2); + + b2Vec3 impulse = -K.Solve33(C); + b2Vec2 P(impulse.x, impulse.y); + + cA -= mA * P; + aA -= iA * (b2Cross(rA, P) + impulse.z); + + cB += mB * P; + aB += iB * (b2Cross(rB, P) + impulse.z); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2WeldJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WeldJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +void b2WeldJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WeldJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2WeldJoint.h b/external/box2d/Dynamics/Joints/b2WeldJoint.h new file mode 100644 index 0000000000..751c6a8770 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2WeldJoint.h @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WELD_JOINT_H +#define B2_WELD_JOINT_H + +#include + +/// Weld joint definition. You need to specify local anchor points +/// where they are attached and the relative body angle. The position +/// of the anchor points is important for computing the reaction torque. +struct b2WeldJointDef : public b2JointDef +{ + b2WeldJointDef() + { + type = e_weldJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// The mass-spring-damper frequency in Hertz. Rotation only. + /// Disable softness with a value of 0. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A weld joint essentially glues two bodies together. A weld joint may +/// distort somewhat because the island constraint solver is approximate. +class b2WeldJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz) { m_frequencyHz = hz; } + float32 GetFrequency() const { return m_frequencyHz; } + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } + float32 GetDampingRatio() const { return m_dampingRatio; } + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + + b2WeldJoint(const b2WeldJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_referenceAngle; + float32 m_gamma; + b2Vec3 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; +}; + +#endif diff --git a/external/box2d/Dynamics/Joints/b2WheelJoint.cpp b/external/box2d/Dynamics/Joints/b2WheelJoint.cpp new file mode 100644 index 0000000000..6253437706 --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2WheelJoint.cpp @@ -0,0 +1,419 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include + +// Linear constraint (point-to-line) +// d = pB - pA = xB + rB - xA - rA +// C = dot(ay, d) +// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) +// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) +// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] + +// Spring linear constraint +// C = dot(ax, d) +// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) +// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] + +// Motor rotational constraint +// Cdot = wB - wA +// J = [0 0 -1 0 0 1] + +void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); +} + +b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + + m_mass = 0.0f; + m_impulse = 0.0f; + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + m_springMass = 0.0f; + m_springImpulse = 0.0f; + + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableMotor = def->enableMotor; + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_bias = 0.0f; + m_gamma = 0.0f; + + m_ax.SetZero(); + m_ay.SetZero(); +} + +void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + // Point to line constraint + { + m_ay = b2Mul(qA, m_localYAxisA); + m_sAy = b2Cross(d + rA, m_ay); + m_sBy = b2Cross(rB, m_ay); + + m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + } + + // Spring constraint + m_springMass = 0.0f; + m_bias = 0.0f; + m_gamma = 0.0f; + if (m_frequencyHz > 0.0f) + { + m_ax = b2Mul(qA, m_localXAxisA); + m_sAx = b2Cross(d + rA, m_ax); + m_sBx = b2Cross(rB, m_ax); + + float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; + + if (invMass > 0.0f) + { + m_springMass = 1.0f / invMass; + + float32 C = b2Dot(d, m_ax); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_springMass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_springMass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + if (m_gamma > 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + + m_bias = C * h * k * m_gamma; + + m_springMass = invMass + m_gamma; + if (m_springMass > 0.0f) + { + m_springMass = 1.0f / m_springMass; + } + } + } + else + { + m_springImpulse = 0.0f; + } + + // Rotational motor + if (m_enableMotor) + { + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + else + { + m_motorMass = 0.0f; + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_springImpulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; + float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; + float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; + + vA -= m_invMassA * P; + wA -= m_invIA * LA; + + vB += m_invMassB * P; + wB += m_invIB * LB; + } + else + { + m_impulse = 0.0f; + m_springImpulse = 0.0f; + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Solve spring constraint + { + float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; + float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); + m_springImpulse += impulse; + + b2Vec2 P = impulse * m_ax; + float32 LA = impulse * m_sAx; + float32 LB = impulse * m_sBx; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + // Solve rotational motor constraint + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve point to line constraint + { + float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 P = impulse * m_ay; + float32 LA = impulse * m_sAy; + float32 LB = impulse * m_sBy; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + b2Vec2 ay = b2Mul(qA, m_localYAxisA); + + float32 sAy = b2Cross(d + rA, ay); + float32 sBy = b2Cross(rB, ay); + + float32 C = b2Dot(d, ay); + + float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; + + float32 impulse; + if (k != 0.0f) + { + impulse = - C / k; + } + else + { + impulse = 0.0f; + } + + b2Vec2 P = impulse * ay; + float32 LA = impulse * sAy; + float32 LB = impulse * sBy; + + cA -= m_invMassA * P; + aA -= m_invIA * LA; + cB += m_invMassB * P; + aB += m_invIB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) <= b2_linearSlop; +} + +b2Vec2 b2WheelJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WheelJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); +} + +float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +float32 b2WheelJoint::GetJointTranslation() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2WheelJoint::GetJointSpeed() const +{ + float32 wA = m_bodyA->m_angularVelocity; + float32 wB = m_bodyB->m_angularVelocity; + return wB - wA; +} + +bool b2WheelJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2WheelJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2WheelJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2WheelJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2WheelJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WheelJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/box2d/Dynamics/Joints/b2WheelJoint.h b/external/box2d/Dynamics/Joints/b2WheelJoint.h new file mode 100644 index 0000000000..ede1b08b7c --- /dev/null +++ b/external/box2d/Dynamics/Joints/b2WheelJoint.h @@ -0,0 +1,213 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WHEEL_JOINT_H +#define B2_WHEEL_JOINT_H + +#include + +/// Wheel joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct b2WheelJointDef : public b2JointDef +{ + b2WheelJointDef() + { + type = e_wheelJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + enableMotor = false; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + frequencyHz = 2.0f; + dampingRatio = 0.7f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation axis in bodyA. + b2Vec2 localAxisA; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorTorque; + + /// The desired motor speed in radians per second. + float32 motorSpeed; + + /// Suspension frequency, zero indicates no suspension + float32 frequencyHz; + + /// Suspension damping ratio, one indicates critical damping + float32 dampingRatio; +}; + +/// A wheel joint. This joint provides two degrees of freedom: translation +/// along an axis fixed in bodyA and rotation in the plane. You can use a +/// joint limit to restrict the range of motion and a joint motor to drive +/// the rotation or to model rotational friction. +/// This joint is designed for vehicle suspensions. +class b2WheelJoint : public b2Joint +{ +public: + void GetDefinition(b2WheelJointDef* def) const; + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in radians per second. + float32 GetMotorSpeed() const; + + /// Set/Get the maximum motor force, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const; + + /// Get the current motor torque given the inverse time step, usually in N-m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. + void SetSpringFrequencyHz(float32 hz); + float32 GetSpringFrequencyHz() const; + + /// Set/Get the spring damping ratio + void SetSpringDampingRatio(float32 ratio); + float32 GetSpringDampingRatio() const; + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + b2WheelJoint(const b2WheelJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + + float32 m_impulse; + float32 m_motorImpulse; + float32 m_springImpulse; + + float32 m_maxMotorTorque; + float32 m_motorSpeed; + bool m_enableMotor; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + + b2Vec2 m_ax, m_ay; + float32 m_sAx, m_sBx; + float32 m_sAy, m_sBy; + + float32 m_mass; + float32 m_motorMass; + float32 m_springMass; + + float32 m_bias; + float32 m_gamma; +}; + +inline float32 b2WheelJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +inline float32 b2WheelJoint::GetMaxMotorTorque() const +{ + return m_maxMotorTorque; +} + +inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2WheelJoint::GetSpringFrequencyHz() const +{ + return m_frequencyHz; +} + +inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2WheelJoint::GetSpringDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/external/box2d/Dynamics/b2Body.cpp b/external/box2d/Dynamics/b2Body.cpp new file mode 100644 index 0000000000..b22b574023 --- /dev/null +++ b/external/box2d/Dynamics/b2Body.cpp @@ -0,0 +1,514 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include +#include +#include + +b2Body::b2Body(const b2BodyDef* bd, b2World* world) +{ + b2Assert(bd->position.IsValid()); + b2Assert(bd->linearVelocity.IsValid()); + b2Assert(b2IsValid(bd->angle)); + b2Assert(b2IsValid(bd->angularVelocity)); + b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); + b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); + + m_flags = 0; + + if (bd->bullet) + { + m_flags |= e_bulletFlag; + } + if (bd->fixedRotation) + { + m_flags |= e_fixedRotationFlag; + } + if (bd->allowSleep) + { + m_flags |= e_autoSleepFlag; + } + if (bd->awake) + { + m_flags |= e_awakeFlag; + } + if (bd->active) + { + m_flags |= e_activeFlag; + } + + m_world = world; + + m_xf.p = bd->position; + m_xf.q.Set(bd->angle); + + m_sweep.localCenter.SetZero(); + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = bd->angle; + m_sweep.a = bd->angle; + m_sweep.alpha0 = 0.0f; + + m_jointList = NULL; + m_contactList = NULL; + m_prev = NULL; + m_next = NULL; + + m_linearVelocity = bd->linearVelocity; + m_angularVelocity = bd->angularVelocity; + + m_linearDamping = bd->linearDamping; + m_angularDamping = bd->angularDamping; + m_gravityScale = bd->gravityScale; + + m_force.SetZero(); + m_torque = 0.0f; + + m_sleepTime = 0.0f; + + m_type = bd->type; + + if (m_type == b2_dynamicBody) + { + m_mass = 1.0f; + m_invMass = 1.0f; + } + else + { + m_mass = 0.0f; + m_invMass = 0.0f; + } + + m_I = 0.0f; + m_invI = 0.0f; + + m_userData = bd->userData; + + m_fixtureList = NULL; + m_fixtureCount = 0; +} + +b2Body::~b2Body() +{ + // shapes and joints are destroyed in b2World::Destroy +} + +void b2Body::SetType(b2BodyType type) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type == type) + { + return; + } + + m_type = type; + + ResetMassData(); + + if (m_type == b2_staticBody) + { + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_sweep.a0 = m_sweep.a; + m_sweep.c0 = m_sweep.c; + SynchronizeFixtures(); + } + + SetAwake(true); + + m_force.SetZero(); + m_torque = 0.0f; + + // Since the body type changed, we need to flag contacts for filtering. + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Refilter(); + } +} + +b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return NULL; + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + void* memory = allocator->Allocate(sizeof(b2Fixture)); + b2Fixture* fixture = new (memory) b2Fixture; + fixture->Create(allocator, this, def); + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->CreateProxies(broadPhase, m_xf); + } + + fixture->m_next = m_fixtureList; + m_fixtureList = fixture; + ++m_fixtureCount; + + fixture->m_body = this; + + // Adjust mass properties if needed. + if (fixture->m_density > 0.0f) + { + ResetMassData(); + } + + // Let the world know we have a new fixture. This will cause new contacts + // to be created at the beginning of the next time step. + m_world->m_flags |= b2World::e_newFixture; + + return fixture; +} + +b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) +{ + b2FixtureDef def; + def.shape = shape; + def.density = density; + + return CreateFixture(&def); +} + +void b2Body::DestroyFixture(b2Fixture* fixture) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + b2Assert(fixture->m_body == this); + + // Remove the fixture from this body's singly linked list. + b2Assert(m_fixtureCount > 0); + b2Fixture** node = &m_fixtureList; + bool found = false; + while (*node != NULL) + { + if (*node == fixture) + { + *node = fixture->m_next; + found = true; + break; + } + + node = &(*node)->m_next; + } + + // You tried to remove a shape that is not attached to this body. + b2Assert(found); + + // Destroy any contacts associated with the fixture. + b2ContactEdge* edge = m_contactList; + while (edge) + { + b2Contact* c = edge->contact; + edge = edge->next; + + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + + if (fixture == fixtureA || fixture == fixtureB) + { + // This destroys the contact and removes it from + // this body's contact list. + m_world->m_contactManager.Destroy(c); + } + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->DestroyProxies(broadPhase); + } + + fixture->Destroy(allocator); + fixture->m_body = NULL; + fixture->m_next = NULL; + fixture->~b2Fixture(); + allocator->Free(fixture, sizeof(b2Fixture)); + + --m_fixtureCount; + + // Reset the mass data. + ResetMassData(); +} + +void b2Body::ResetMassData() +{ + // Compute mass data from shapes. Each shape has its own density. + m_mass = 0.0f; + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + m_sweep.localCenter.SetZero(); + + // Static and kinematic bodies have zero mass. + if (m_type == b2_staticBody || m_type == b2_kinematicBody) + { + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = m_sweep.a; + return; + } + + b2Assert(m_type == b2_dynamicBody); + + // Accumulate mass over all fixtures. + b2Vec2 localCenter = b2Vec2_zero; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + if (f->m_density == 0.0f) + { + continue; + } + + b2MassData massData; + f->GetMassData(&massData); + m_mass += massData.mass; + localCenter += massData.mass * massData.center; + m_I += massData.I; + } + + // Compute center of mass. + if (m_mass > 0.0f) + { + m_invMass = 1.0f / m_mass; + localCenter *= m_invMass; + } + else + { + // Force all dynamic bodies to have a positive mass. + m_mass = 1.0f; + m_invMass = 1.0f; + } + + if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) + { + // Center the inertia about the center of mass. + m_I -= m_mass * b2Dot(localCenter, localCenter); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + + } + else + { + m_I = 0.0f; + m_invI = 0.0f; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = localCenter; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +void b2Body::SetMassData(const b2MassData* massData) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type != b2_dynamicBody) + { + return; + } + + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + + m_mass = massData->mass; + if (m_mass <= 0.0f) + { + m_mass = 1.0f; + } + + m_invMass = 1.0f / m_mass; + + if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) + { + m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = massData->center; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +bool b2Body::ShouldCollide(const b2Body* other) const +{ + // At least one body should be dynamic. + if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) + { + return false; + } + + // Does a joint prevent collision? + for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) + { + if (jn->other == other) + { + if (jn->joint->m_collideConnected == false) + { + return false; + } + } + } + + return true; +} + +void b2Body::SetTransform(const b2Vec2& position, float32 angle) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + m_xf.q.Set(angle); + m_xf.p = position; + + m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + m_sweep.a = angle; + + m_sweep.c0 = m_sweep.c; + m_sweep.a0 = angle; + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, m_xf, m_xf); + } + + m_world->m_contactManager.FindNewContacts(); +} + +void b2Body::SynchronizeFixtures() +{ + b2Transform xf1; + xf1.q.Set(m_sweep.a0); + xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, xf1, m_xf); + } +} + +void b2Body::SetActive(bool flag) +{ + b2Assert(m_world->IsLocked() == false); + + if (flag == IsActive()) + { + return; + } + + if (flag) + { + m_flags |= e_activeFlag; + + // Create all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->CreateProxies(broadPhase, m_xf); + } + + // Contacts are created the next time step. + } + else + { + m_flags &= ~e_activeFlag; + + // Destroy all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->DestroyProxies(broadPhase); + } + + // Destroy the attached contacts. + b2ContactEdge* ce = m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_world->m_contactManager.Destroy(ce0->contact); + } + m_contactList = NULL; + } +} + +void b2Body::Dump() +{ + int32 bodyIndex = m_islandIndex; + + b2Log("{\n"); + b2Log(" b2BodyDef bd;\n"); + b2Log(" bd.type = b2BodyType(%d);\n", m_type); + b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); + b2Log(" bd.angle = %.15lef;\n", m_sweep.a); + b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); + b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); + b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); + b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); + b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); + b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); + b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); + b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); + b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); + b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); + b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); + b2Log("\n"); + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + b2Log(" {\n"); + f->Dump(bodyIndex); + b2Log(" }\n"); + } + b2Log("}\n"); +} \ No newline at end of file diff --git a/external/box2d/Dynamics/b2Body.h b/external/box2d/Dynamics/b2Body.h new file mode 100644 index 0000000000..e2d16bf630 --- /dev/null +++ b/external/box2d/Dynamics/b2Body.h @@ -0,0 +1,846 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_BODY_H +#define B2_BODY_H + +#include +#include +#include + +class b2Fixture; +class b2Joint; +class b2Contact; +class b2Controller; +class b2World; +struct b2FixtureDef; +struct b2JointEdge; +struct b2ContactEdge; + +/// The body type. +/// static: zero mass, zero velocity, may be manually moved +/// kinematic: zero mass, non-zero velocity set by user, moved by solver +/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver +enum b2BodyType +{ + b2_staticBody = 0, + b2_kinematicBody, + b2_dynamicBody + + // TODO_ERIN + //b2_bulletBody, +}; + +/// A body definition holds all the data needed to construct a rigid body. +/// You can safely re-use body definitions. Shapes are added to a body after construction. +struct b2BodyDef +{ + /// This constructor sets the body definition default values. + b2BodyDef() + { + userData = NULL; + position.Set(0.0f, 0.0f); + angle = 0.0f; + linearVelocity.Set(0.0f, 0.0f); + angularVelocity = 0.0f; + linearDamping = 0.0f; + angularDamping = 0.0f; + allowSleep = true; + awake = true; + fixedRotation = false; + bullet = false; + type = b2_staticBody; + active = true; + gravityScale = 1.0f; + } + + /// The body type: static, kinematic, or dynamic. + /// Note: if a dynamic body would have zero mass, the mass is set to one. + b2BodyType type; + + /// The world position of the body. Avoid creating bodies at the origin + /// since this can lead to many overlapping shapes. + b2Vec2 position; + + /// The world angle of the body in radians. + float32 angle; + + /// The linear velocity of the body's origin in world co-ordinates. + b2Vec2 linearVelocity; + + /// The angular velocity of the body. + float32 angularVelocity; + + /// Linear damping is use to reduce the linear velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 linearDamping; + + /// Angular damping is use to reduce the angular velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 angularDamping; + + /// Set this flag to false if this body should never fall asleep. Note that + /// this increases CPU usage. + bool allowSleep; + + /// Is this body initially awake or sleeping? + bool awake; + + /// Should this body be prevented from rotating? Useful for characters. + bool fixedRotation; + + /// Is this a fast moving body that should be prevented from tunneling through + /// other moving bodies? Note that all bodies are prevented from tunneling through + /// kinematic and static bodies. This setting is only considered on dynamic bodies. + /// @warning You should use this flag sparingly since it increases processing time. + bool bullet; + + /// Does this body start out active? + bool active; + + /// Use this to store application specific body data. + void* userData; + + /// Scale the gravity applied to this body. + float32 gravityScale; +}; + +/// A rigid body. These are created via b2World::CreateBody. +class b2Body +{ +public: + /// Creates a fixture and attach it to this body. Use this function if you need + /// to set some fixture parameters, like friction. Otherwise you can create the + /// fixture directly from a shape. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// Contacts are not created until the next time step. + /// @param def the fixture definition. + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2FixtureDef* def); + + /// Creates a fixture from a shape and attach it to this body. + /// This is a convenience function. Use b2FixtureDef if you need to set parameters + /// like friction, restitution, user data, or filtering. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// @param shape the shape to be cloned. + /// @param density the shape density (set to zero for static bodies). + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2Shape* shape, float32 density); + + /// Destroy a fixture. This removes the fixture from the broad-phase and + /// destroys all contacts associated with this fixture. This will + /// automatically adjust the mass of the body if the body is dynamic and the + /// fixture has positive density. + /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. + /// @param fixture the fixture to be removed. + /// @warning This function is locked during callbacks. + void DestroyFixture(b2Fixture* fixture); + + /// Set the position of the body's origin and rotation. + /// This breaks any contacts and wakes the other bodies. + /// Manipulating a body's transform may cause non-physical behavior. + /// @param position the world position of the body's local origin. + /// @param angle the world rotation in radians. + void SetTransform(const b2Vec2& position, float32 angle); + + /// Get the body transform for the body's origin. + /// @return the world transform of the body's origin. + const b2Transform& GetTransform() const; + + /// Get the world body origin position. + /// @return the world position of the body's origin. + const b2Vec2& GetPosition() const; + + /// Get the angle in radians. + /// @return the current world rotation angle in radians. + float32 GetAngle() const; + + /// Get the world position of the center of mass. + const b2Vec2& GetWorldCenter() const; + + /// Get the local position of the center of mass. + const b2Vec2& GetLocalCenter() const; + + /// Set the linear velocity of the center of mass. + /// @param v the new linear velocity of the center of mass. + void SetLinearVelocity(const b2Vec2& v); + + /// Get the linear velocity of the center of mass. + /// @return the linear velocity of the center of mass. + b2Vec2 GetLinearVelocity() const; + + /// Set the angular velocity. + /// @param omega the new angular velocity in radians/second. + void SetAngularVelocity(float32 omega); + + /// Get the angular velocity. + /// @return the angular velocity in radians/second. + float32 GetAngularVelocity() const; + + /// Apply a force at a world point. If the force is not + /// applied at the center of mass, it will generate a torque and + /// affect the angular velocity. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + /// @param point the world position of the point of application. + void ApplyForce(const b2Vec2& force, const b2Vec2& point); + + /// Apply a force to the center of mass. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + void ApplyForceToCenter(const b2Vec2& force); + + /// Apply a torque. This affects the angular velocity + /// without affecting the linear velocity of the center of mass. + /// This wakes up the body. + /// @param torque about the z-axis (out of the screen), usually in N-m. + void ApplyTorque(float32 torque); + + /// Apply an impulse at a point. This immediately modifies the velocity. + /// It also modifies the angular velocity if the point of application + /// is not at the center of mass. This wakes up the body. + /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. + /// @param point the world position of the point of application. + void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point); + + /// Apply an angular impulse. + /// @param impulse the angular impulse in units of kg*m*m/s + void ApplyAngularImpulse(float32 impulse); + + /// Get the total mass of the body. + /// @return the mass, usually in kilograms (kg). + float32 GetMass() const; + + /// Get the rotational inertia of the body about the local origin. + /// @return the rotational inertia, usually in kg-m^2. + float32 GetInertia() const; + + /// Get the mass data of the body. + /// @return a struct containing the mass, inertia and center of the body. + void GetMassData(b2MassData* data) const; + + /// Set the mass properties to override the mass properties of the fixtures. + /// Note that this changes the center of mass position. + /// Note that creating or destroying fixtures can also alter the mass. + /// This function has no effect if the body isn't dynamic. + /// @param massData the mass properties. + void SetMassData(const b2MassData* data); + + /// This resets the mass properties to the sum of the mass properties of the fixtures. + /// This normally does not need to be called unless you called SetMassData to override + /// the mass and you later want to reset the mass. + void ResetMassData(); + + /// Get the world coordinates of a point given the local coordinates. + /// @param localPoint a point on the body measured relative the the body's origin. + /// @return the same point expressed in world coordinates. + b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; + + /// Get the world coordinates of a vector given the local coordinates. + /// @param localVector a vector fixed in the body. + /// @return the same vector expressed in world coordinates. + b2Vec2 GetWorldVector(const b2Vec2& localVector) const; + + /// Gets a local point relative to the body's origin given a world point. + /// @param a point in world coordinates. + /// @return the corresponding local point relative to the body's origin. + b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; + + /// Gets a local vector given a world vector. + /// @param a vector in world coordinates. + /// @return the corresponding local vector. + b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; + + /// Get the world linear velocity of a world point attached to this body. + /// @param a point in world coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; + + /// Get the world velocity of a local point. + /// @param a point in local coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; + + /// Get the linear damping of the body. + float32 GetLinearDamping() const; + + /// Set the linear damping of the body. + void SetLinearDamping(float32 linearDamping); + + /// Get the angular damping of the body. + float32 GetAngularDamping() const; + + /// Set the angular damping of the body. + void SetAngularDamping(float32 angularDamping); + + /// Get the gravity scale of the body. + float32 GetGravityScale() const; + + /// Set the gravity scale of the body. + void SetGravityScale(float32 scale); + + /// Set the type of this body. This may alter the mass and velocity. + void SetType(b2BodyType type); + + /// Get the type of this body. + b2BodyType GetType() const; + + /// Should this body be treated like a bullet for continuous collision detection? + void SetBullet(bool flag); + + /// Is this body treated like a bullet for continuous collision detection? + bool IsBullet() const; + + /// You can disable sleeping on this body. If you disable sleeping, the + /// body will be woken. + void SetSleepingAllowed(bool flag); + + /// Is this body allowed to sleep + bool IsSleepingAllowed() const; + + /// Set the sleep state of the body. A sleeping body has very + /// low CPU cost. + /// @param flag set to true to put body to sleep, false to wake it. + void SetAwake(bool flag); + + /// Get the sleeping state of this body. + /// @return true if the body is sleeping. + bool IsAwake() const; + + /// Set the active state of the body. An inactive body is not + /// simulated and cannot be collided with or woken up. + /// If you pass a flag of true, all fixtures will be added to the + /// broad-phase. + /// If you pass a flag of false, all fixtures will be removed from + /// the broad-phase and all contacts will be destroyed. + /// Fixtures and joints are otherwise unaffected. You may continue + /// to create/destroy fixtures and joints on inactive bodies. + /// Fixtures on an inactive body are implicitly inactive and will + /// not participate in collisions, ray-casts, or queries. + /// Joints connected to an inactive body are implicitly inactive. + /// An inactive body is still owned by a b2World object and remains + /// in the body list. + void SetActive(bool flag); + + /// Get the active state of the body. + bool IsActive() const; + + /// Set this body to have fixed rotation. This causes the mass + /// to be reset. + void SetFixedRotation(bool flag); + + /// Does this body have fixed rotation? + bool IsFixedRotation() const; + + /// Get the list of all fixtures attached to this body. + b2Fixture* GetFixtureList(); + const b2Fixture* GetFixtureList() const; + + /// Get the list of all joints attached to this body. + b2JointEdge* GetJointList(); + const b2JointEdge* GetJointList() const; + + /// Get the list of all contacts attached to this body. + /// @warning this list changes during the time step and you may + /// miss some collisions if you don't use b2ContactListener. + b2ContactEdge* GetContactList(); + const b2ContactEdge* GetContactList() const; + + /// Get the next body in the world's body list. + b2Body* GetNext(); + const b2Body* GetNext() const; + + /// Get the user data pointer that was provided in the body definition. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Get the parent world of this body. + b2World* GetWorld(); + const b2World* GetWorld() const; + + /// Dump this body to a log file + void Dump(); + +private: + + friend class b2World; + friend class b2Island; + friend class b2ContactManager; + friend class b2ContactSolver; + friend class b2Contact; + + friend class b2DistanceJoint; + friend class b2GearJoint; + friend class b2WheelJoint; + friend class b2MouseJoint; + friend class b2PrismaticJoint; + friend class b2PulleyJoint; + friend class b2RevoluteJoint; + friend class b2WeldJoint; + friend class b2FrictionJoint; + friend class b2RopeJoint; + + // m_flags + enum + { + e_islandFlag = 0x0001, + e_awakeFlag = 0x0002, + e_autoSleepFlag = 0x0004, + e_bulletFlag = 0x0008, + e_fixedRotationFlag = 0x0010, + e_activeFlag = 0x0020, + e_toiFlag = 0x0040 + }; + + b2Body(const b2BodyDef* bd, b2World* world); + ~b2Body(); + + void SynchronizeFixtures(); + void SynchronizeTransform(); + + // This is used to prevent connected bodies from colliding. + // It may lie, depending on the collideConnected flag. + bool ShouldCollide(const b2Body* other) const; + + void Advance(float32 t); + + b2BodyType m_type; + + uint16 m_flags; + + int32 m_islandIndex; + + b2Transform m_xf; // the body origin transform + b2Sweep m_sweep; // the swept motion for CCD + + b2Vec2 m_linearVelocity; + float32 m_angularVelocity; + + b2Vec2 m_force; + float32 m_torque; + + b2World* m_world; + b2Body* m_prev; + b2Body* m_next; + + b2Fixture* m_fixtureList; + int32 m_fixtureCount; + + b2JointEdge* m_jointList; + b2ContactEdge* m_contactList; + + float32 m_mass, m_invMass; + + // Rotational inertia about the center of mass. + float32 m_I, m_invI; + + float32 m_linearDamping; + float32 m_angularDamping; + float32 m_gravityScale; + + float32 m_sleepTime; + + void* m_userData; +}; + +inline b2BodyType b2Body::GetType() const +{ + return m_type; +} + +inline const b2Transform& b2Body::GetTransform() const +{ + return m_xf; +} + +inline const b2Vec2& b2Body::GetPosition() const +{ + return m_xf.p; +} + +inline float32 b2Body::GetAngle() const +{ + return m_sweep.a; +} + +inline const b2Vec2& b2Body::GetWorldCenter() const +{ + return m_sweep.c; +} + +inline const b2Vec2& b2Body::GetLocalCenter() const +{ + return m_sweep.localCenter; +} + +inline void b2Body::SetLinearVelocity(const b2Vec2& v) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (b2Dot(v,v) > 0.0f) + { + SetAwake(true); + } + + m_linearVelocity = v; +} + +inline b2Vec2 b2Body::GetLinearVelocity() const +{ + return m_linearVelocity; +} + +inline void b2Body::SetAngularVelocity(float32 w) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (w * w > 0.0f) + { + SetAwake(true); + } + + m_angularVelocity = w; +} + +inline float32 b2Body::GetAngularVelocity() const +{ + return m_angularVelocity; +} + +inline float32 b2Body::GetMass() const +{ + return m_mass; +} + +inline float32 b2Body::GetInertia() const +{ + return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); +} + +inline void b2Body::GetMassData(b2MassData* data) const +{ + data->mass = m_mass; + data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); + data->center = m_sweep.localCenter; +} + +inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const +{ + return b2Mul(m_xf, localPoint); +} + +inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const +{ + return b2Mul(m_xf.q, localVector); +} + +inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const +{ + return b2MulT(m_xf, worldPoint); +} + +inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const +{ + return b2MulT(m_xf.q, worldVector); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const +{ + return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const +{ + return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); +} + +inline float32 b2Body::GetLinearDamping() const +{ + return m_linearDamping; +} + +inline void b2Body::SetLinearDamping(float32 linearDamping) +{ + m_linearDamping = linearDamping; +} + +inline float32 b2Body::GetAngularDamping() const +{ + return m_angularDamping; +} + +inline void b2Body::SetAngularDamping(float32 angularDamping) +{ + m_angularDamping = angularDamping; +} + +inline float32 b2Body::GetGravityScale() const +{ + return m_gravityScale; +} + +inline void b2Body::SetGravityScale(float32 scale) +{ + m_gravityScale = scale; +} + +inline void b2Body::SetBullet(bool flag) +{ + if (flag) + { + m_flags |= e_bulletFlag; + } + else + { + m_flags &= ~e_bulletFlag; + } +} + +inline bool b2Body::IsBullet() const +{ + return (m_flags & e_bulletFlag) == e_bulletFlag; +} + +inline void b2Body::SetAwake(bool flag) +{ + if (flag) + { + if ((m_flags & e_awakeFlag) == 0) + { + m_flags |= e_awakeFlag; + m_sleepTime = 0.0f; + } + } + else + { + m_flags &= ~e_awakeFlag; + m_sleepTime = 0.0f; + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_force.SetZero(); + m_torque = 0.0f; + } +} + +inline bool b2Body::IsAwake() const +{ + return (m_flags & e_awakeFlag) == e_awakeFlag; +} + +inline bool b2Body::IsActive() const +{ + return (m_flags & e_activeFlag) == e_activeFlag; +} + +inline void b2Body::SetFixedRotation(bool flag) +{ + if (flag) + { + m_flags |= e_fixedRotationFlag; + } + else + { + m_flags &= ~e_fixedRotationFlag; + } + + ResetMassData(); +} + +inline bool b2Body::IsFixedRotation() const +{ + return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; +} + +inline void b2Body::SetSleepingAllowed(bool flag) +{ + if (flag) + { + m_flags |= e_autoSleepFlag; + } + else + { + m_flags &= ~e_autoSleepFlag; + SetAwake(true); + } +} + +inline bool b2Body::IsSleepingAllowed() const +{ + return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; +} + +inline b2Fixture* b2Body::GetFixtureList() +{ + return m_fixtureList; +} + +inline const b2Fixture* b2Body::GetFixtureList() const +{ + return m_fixtureList; +} + +inline b2JointEdge* b2Body::GetJointList() +{ + return m_jointList; +} + +inline const b2JointEdge* b2Body::GetJointList() const +{ + return m_jointList; +} + +inline b2ContactEdge* b2Body::GetContactList() +{ + return m_contactList; +} + +inline const b2ContactEdge* b2Body::GetContactList() const +{ + return m_contactList; +} + +inline b2Body* b2Body::GetNext() +{ + return m_next; +} + +inline const b2Body* b2Body::GetNext() const +{ + return m_next; +} + +inline void b2Body::SetUserData(void* data) +{ + m_userData = data; +} + +inline void* b2Body::GetUserData() const +{ + return m_userData; +} + +inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; + m_torque += b2Cross(point - m_sweep.c, force); +} + +inline void b2Body::ApplyForceToCenter(const b2Vec2& force) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; +} + +inline void b2Body::ApplyTorque(float32 torque) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_torque += torque; +} + +inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_linearVelocity += m_invMass * impulse; + m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); +} + +inline void b2Body::ApplyAngularImpulse(float32 impulse) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_angularVelocity += m_invI * impulse; +} + +inline void b2Body::SynchronizeTransform() +{ + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline void b2Body::Advance(float32 alpha) +{ + // Advance to the new safe time. This doesn't sync the broad-phase. + m_sweep.Advance(alpha); + m_sweep.c = m_sweep.c0; + m_sweep.a = m_sweep.a0; + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline b2World* b2Body::GetWorld() +{ + return m_world; +} + +inline const b2World* b2Body::GetWorld() const +{ + return m_world; +} + +#endif diff --git a/external/box2d/Dynamics/b2ContactManager.cpp b/external/box2d/Dynamics/b2ContactManager.cpp new file mode 100644 index 0000000000..c14cc4ce45 --- /dev/null +++ b/external/box2d/Dynamics/b2ContactManager.cpp @@ -0,0 +1,293 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include + +b2ContactFilter b2_defaultFilter; +b2ContactListener b2_defaultListener; + +b2ContactManager::b2ContactManager() +{ + m_contactList = NULL; + m_contactCount = 0; + m_contactFilter = &b2_defaultFilter; + m_contactListener = &b2_defaultListener; + m_allocator = NULL; +} + +void b2ContactManager::Destroy(b2Contact* c) +{ + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + if (m_contactListener && c->IsTouching()) + { + m_contactListener->EndContact(c); + } + + // Remove from the world. + if (c->m_prev) + { + c->m_prev->m_next = c->m_next; + } + + if (c->m_next) + { + c->m_next->m_prev = c->m_prev; + } + + if (c == m_contactList) + { + m_contactList = c->m_next; + } + + // Remove from body 1 + if (c->m_nodeA.prev) + { + c->m_nodeA.prev->next = c->m_nodeA.next; + } + + if (c->m_nodeA.next) + { + c->m_nodeA.next->prev = c->m_nodeA.prev; + } + + if (&c->m_nodeA == bodyA->m_contactList) + { + bodyA->m_contactList = c->m_nodeA.next; + } + + // Remove from body 2 + if (c->m_nodeB.prev) + { + c->m_nodeB.prev->next = c->m_nodeB.next; + } + + if (c->m_nodeB.next) + { + c->m_nodeB.next->prev = c->m_nodeB.prev; + } + + if (&c->m_nodeB == bodyB->m_contactList) + { + bodyB->m_contactList = c->m_nodeB.next; + } + + // Call the factory. + b2Contact::Destroy(c, m_allocator); + --m_contactCount; +} + +// This is the top level collision call for the time step. Here +// all the narrow phase collision is processed for the world +// contact list. +void b2ContactManager::Collide() +{ + // Update awake contacts. + b2Contact* c = m_contactList; + while (c) + { + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Is this contact flagged for filtering? + if (c->m_flags & b2Contact::e_filterFlag) + { + // Should these bodies collide? + if (bodyB->ShouldCollide(bodyA) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Clear the filtering flag. + c->m_flags &= ~b2Contact::e_filterFlag; + } + + bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; + bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; + + // At least one body must be awake and it must be dynamic or kinematic. + if (activeA == false && activeB == false) + { + c = c->GetNext(); + continue; + } + + int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; + int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; + bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); + + // Here we destroy contacts that cease to overlap in the broad-phase. + if (overlap == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // The contact persists. + c->Update(m_contactListener); + c = c->GetNext(); + } +} + +void b2ContactManager::FindNewContacts() +{ + m_broadPhase.UpdatePairs(this); +} + +void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) +{ + b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; + b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; + + b2Fixture* fixtureA = proxyA->fixture; + b2Fixture* fixtureB = proxyB->fixture; + + int32 indexA = proxyA->childIndex; + int32 indexB = proxyB->childIndex; + + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Are the fixtures on the same body? + if (bodyA == bodyB) + { + return; + } + + // TODO_ERIN use a hash table to remove a potential bottleneck when both + // bodies have a lot of contacts. + // Does a contact already exist? + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + b2Fixture* fA = edge->contact->GetFixtureA(); + b2Fixture* fB = edge->contact->GetFixtureB(); + int32 iA = edge->contact->GetChildIndexA(); + int32 iB = edge->contact->GetChildIndexB(); + + if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) + { + // A contact already exists. + return; + } + + if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) + { + // A contact already exists. + return; + } + } + + edge = edge->next; + } + + // Does a joint override collision? Is at least one body dynamic? + if (bodyB->ShouldCollide(bodyA) == false) + { + return; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + return; + } + + // Call the factory. + b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); + if (c == NULL) + { + return; + } + + // Contact creation may swap fixtures. + fixtureA = c->GetFixtureA(); + fixtureB = c->GetFixtureB(); + indexA = c->GetChildIndexA(); + indexB = c->GetChildIndexB(); + bodyA = fixtureA->GetBody(); + bodyB = fixtureB->GetBody(); + + // Insert into the world. + c->m_prev = NULL; + c->m_next = m_contactList; + if (m_contactList != NULL) + { + m_contactList->m_prev = c; + } + m_contactList = c; + + // Connect to island graph. + + // Connect to body A + c->m_nodeA.contact = c; + c->m_nodeA.other = bodyB; + + c->m_nodeA.prev = NULL; + c->m_nodeA.next = bodyA->m_contactList; + if (bodyA->m_contactList != NULL) + { + bodyA->m_contactList->prev = &c->m_nodeA; + } + bodyA->m_contactList = &c->m_nodeA; + + // Connect to body B + c->m_nodeB.contact = c; + c->m_nodeB.other = bodyA; + + c->m_nodeB.prev = NULL; + c->m_nodeB.next = bodyB->m_contactList; + if (bodyB->m_contactList != NULL) + { + bodyB->m_contactList->prev = &c->m_nodeB; + } + bodyB->m_contactList = &c->m_nodeB; + + // Wake up the bodies + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + ++m_contactCount; +} diff --git a/external/box2d/Dynamics/b2ContactManager.h b/external/box2d/Dynamics/b2ContactManager.h new file mode 100644 index 0000000000..9cb5718145 --- /dev/null +++ b/external/box2d/Dynamics/b2ContactManager.h @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_MANAGER_H +#define B2_CONTACT_MANAGER_H + +#include + +class b2Contact; +class b2ContactFilter; +class b2ContactListener; +class b2BlockAllocator; + +// Delegate of b2World. +class b2ContactManager +{ +public: + b2ContactManager(); + + // Broad-phase callback. + void AddPair(void* proxyUserDataA, void* proxyUserDataB); + + void FindNewContacts(); + + void Destroy(b2Contact* c); + + void Collide(); + + b2BroadPhase m_broadPhase; + b2Contact* m_contactList; + int32 m_contactCount; + b2ContactFilter* m_contactFilter; + b2ContactListener* m_contactListener; + b2BlockAllocator* m_allocator; +}; + +#endif diff --git a/external/box2d/Dynamics/b2Fixture.cpp b/external/box2d/Dynamics/b2Fixture.cpp new file mode 100644 index 0000000000..774a78e5bb --- /dev/null +++ b/external/box2d/Dynamics/b2Fixture.cpp @@ -0,0 +1,303 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2Fixture::b2Fixture() +{ + m_userData = NULL; + m_body = NULL; + m_next = NULL; + m_proxies = NULL; + m_proxyCount = 0; + m_shape = NULL; + m_density = 0.0f; +} + +void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) +{ + m_userData = def->userData; + m_friction = def->friction; + m_restitution = def->restitution; + + m_body = body; + m_next = NULL; + + m_filter = def->filter; + + m_isSensor = def->isSensor; + + m_shape = def->shape->Clone(allocator); + + // Reserve proxy space + int32 childCount = m_shape->GetChildCount(); + m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); + for (int32 i = 0; i < childCount; ++i) + { + m_proxies[i].fixture = NULL; + m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; + } + m_proxyCount = 0; + + m_density = def->density; +} + +void b2Fixture::Destroy(b2BlockAllocator* allocator) +{ + // The proxies must be destroyed before calling this. + b2Assert(m_proxyCount == 0); + + // Free the proxy array. + int32 childCount = m_shape->GetChildCount(); + allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); + m_proxies = NULL; + + // Free the child shape. + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + } + break; + + default: + b2Assert(false); + break; + } + + m_shape = NULL; +} + +void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) +{ + b2Assert(m_proxyCount == 0); + + // Create proxies in the broad-phase. + m_proxyCount = m_shape->GetChildCount(); + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + m_shape->ComputeAABB(&proxy->aabb, xf, i); + proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); + proxy->fixture = this; + proxy->childIndex = i; + } +} + +void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) +{ + // Destroy proxies in the broad-phase. + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + broadPhase->DestroyProxy(proxy->proxyId); + proxy->proxyId = b2BroadPhase::e_nullProxy; + } + + m_proxyCount = 0; +} + +void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) +{ + if (m_proxyCount == 0) + { + return; + } + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + + // Compute an AABB that covers the swept shape (may miss some rotation effect). + b2AABB aabb1, aabb2; + m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); + m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); + + proxy->aabb.Combine(aabb1, aabb2); + + b2Vec2 displacement = transform2.p - transform1.p; + + broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); + } +} + +void b2Fixture::SetFilterData(const b2Filter& filter) +{ + m_filter = filter; + + Refilter(); +} + +void b2Fixture::Refilter() +{ + if (m_body == NULL) + { + return; + } + + // Flag associated contacts for filtering. + b2ContactEdge* edge = m_body->GetContactList(); + while (edge) + { + b2Contact* contact = edge->contact; + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + if (fixtureA == this || fixtureB == this) + { + contact->FlagForFiltering(); + } + + edge = edge->next; + } + + b2World* world = m_body->GetWorld(); + + if (world == NULL) + { + return; + } + + // Touch each proxy so that new pairs may be created + b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; + for (int32 i = 0; i < m_proxyCount; ++i) + { + broadPhase->TouchProxy(m_proxies[i].proxyId); + } +} + +void b2Fixture::SetSensor(bool sensor) +{ + if (sensor != m_isSensor) + { + m_body->SetAwake(true); + m_isSensor = sensor; + } +} + +void b2Fixture::Dump(int32 bodyIndex) +{ + b2Log(" b2FixtureDef fd;\n"); + b2Log(" fd.friction = %.15lef;\n", m_friction); + b2Log(" fd.restitution = %.15lef;\n", m_restitution); + b2Log(" fd.density = %.15lef;\n", m_density); + b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); + b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); + b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); + b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); + + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + b2Log(" b2CircleShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + b2Log(" b2EdgeShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); + b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); + b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); + b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); + b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); + b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + b2Log(" b2PolygonShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); + for (int32 i = 0; i < s->m_vertexCount; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + b2Log(" b2ChainShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", s->m_count); + for (int32 i = 0; i < s->m_count; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); + b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); + b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); + b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); + b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); + } + break; + + default: + return; + } + + b2Log("\n"); + b2Log(" fd.shape = &shape;\n"); + b2Log("\n"); + b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); +} diff --git a/external/box2d/Dynamics/b2Fixture.h b/external/box2d/Dynamics/b2Fixture.h new file mode 100644 index 0000000000..d390410b93 --- /dev/null +++ b/external/box2d/Dynamics/b2Fixture.h @@ -0,0 +1,345 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_FIXTURE_H +#define B2_FIXTURE_H + +#include +#include +#include + +class b2BlockAllocator; +class b2Body; +class b2BroadPhase; +class b2Fixture; + +/// This holds contact filtering data. +struct b2Filter +{ + b2Filter() + { + categoryBits = 0x0001; + maskBits = 0xFFFF; + groupIndex = 0; + } + + /// The collision category bits. Normally you would just set one bit. + uint16 categoryBits; + + /// The collision mask bits. This states the categories that this + /// shape would accept for collision. + uint16 maskBits; + + /// Collision groups allow a certain group of objects to never collide (negative) + /// or always collide (positive). Zero means no collision group. Non-zero group + /// filtering always wins against the mask bits. + int16 groupIndex; +}; + +/// A fixture definition is used to create a fixture. This class defines an +/// abstract fixture definition. You can reuse fixture definitions safely. +struct b2FixtureDef +{ + /// The constructor sets the default fixture definition values. + b2FixtureDef() + { + shape = NULL; + userData = NULL; + friction = 0.2f; + restitution = 0.0f; + density = 0.0f; + isSensor = false; + } + + /// The shape, this must be set. The shape will be cloned, so you + /// can create the shape on the stack. + const b2Shape* shape; + + /// Use this to store application specific fixture data. + void* userData; + + /// The friction coefficient, usually in the range [0,1]. + float32 friction; + + /// The restitution (elasticity) usually in the range [0,1]. + float32 restitution; + + /// The density, usually in kg/m^2. + float32 density; + + /// A sensor shape collects contact information but never generates a collision + /// response. + bool isSensor; + + /// Contact filtering data. + b2Filter filter; +}; + +/// This proxy is used internally to connect fixtures to the broad-phase. +struct b2FixtureProxy +{ + b2AABB aabb; + b2Fixture* fixture; + int32 childIndex; + int32 proxyId; +}; + +/// A fixture is used to attach a shape to a body for collision detection. A fixture +/// inherits its transform from its parent. Fixtures hold additional non-geometric data +/// such as friction, collision filters, etc. +/// Fixtures are created via b2Body::CreateFixture. +/// @warning you cannot reuse fixtures. +class b2Fixture +{ +public: + /// Get the type of the child shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + b2Shape::Type GetType() const; + + /// Get the child shape. You can modify the child shape, however you should not change the + /// number of vertices because this will crash some collision caching mechanisms. + /// Manipulating the shape may lead to non-physical behavior. + b2Shape* GetShape(); + const b2Shape* GetShape() const; + + /// Set if this fixture is a sensor. + void SetSensor(bool sensor); + + /// Is this fixture a sensor (non-solid)? + /// @return the true if the shape is a sensor. + bool IsSensor() const; + + /// Set the contact filtering data. This will not update contacts until the next time + /// step when either parent body is active and awake. + /// This automatically calls Refilter. + void SetFilterData(const b2Filter& filter); + + /// Get the contact filtering data. + const b2Filter& GetFilterData() const; + + /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. + void Refilter(); + + /// Get the parent body of this fixture. This is NULL if the fixture is not attached. + /// @return the parent body. + b2Body* GetBody(); + const b2Body* GetBody() const; + + /// Get the next fixture in the parent body's fixture list. + /// @return the next shape. + b2Fixture* GetNext(); + const b2Fixture* GetNext() const; + + /// Get the user data that was assigned in the fixture definition. Use this to + /// store your application specific data. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Test a point for containment in this fixture. + /// @param p a point in world coordinates. + bool TestPoint(const b2Vec2& p) const; + + /// Cast a ray against this shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; + + /// Get the mass data for this fixture. The mass data is based on the density and + /// the shape. The rotational inertia is about the shape's origin. This operation + /// may be expensive. + void GetMassData(b2MassData* massData) const; + + /// Set the density of this fixture. This will _not_ automatically adjust the mass + /// of the body. You must call b2Body::ResetMassData to update the body's mass. + void SetDensity(float32 density); + + /// Get the density of this fixture. + float32 GetDensity() const; + + /// Get the coefficient of friction. + float32 GetFriction() const; + + /// Set the coefficient of friction. This will _not_ change the friction of + /// existing contacts. + void SetFriction(float32 friction); + + /// Get the coefficient of restitution. + float32 GetRestitution() const; + + /// Set the coefficient of restitution. This will _not_ change the restitution of + /// existing contacts. + void SetRestitution(float32 restitution); + + /// Get the fixture's AABB. This AABB may be enlarge and/or stale. + /// If you need a more accurate AABB, compute it using the shape and + /// the body transform. + const b2AABB& GetAABB(int32 childIndex) const; + + /// Dump this fixture to the log file. + void Dump(int32 bodyIndex); + +protected: + + friend class b2Body; + friend class b2World; + friend class b2Contact; + friend class b2ContactManager; + + b2Fixture(); + + // We need separation create/destroy functions from the constructor/destructor because + // the destructor cannot access the allocator (no destructor arguments allowed by C++). + void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); + void Destroy(b2BlockAllocator* allocator); + + // These support body activation/deactivation. + void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); + void DestroyProxies(b2BroadPhase* broadPhase); + + void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); + + float32 m_density; + + b2Fixture* m_next; + b2Body* m_body; + + b2Shape* m_shape; + + float32 m_friction; + float32 m_restitution; + + b2FixtureProxy* m_proxies; + int32 m_proxyCount; + + b2Filter m_filter; + + bool m_isSensor; + + void* m_userData; +}; + +inline b2Shape::Type b2Fixture::GetType() const +{ + return m_shape->GetType(); +} + +inline b2Shape* b2Fixture::GetShape() +{ + return m_shape; +} + +inline const b2Shape* b2Fixture::GetShape() const +{ + return m_shape; +} + +inline bool b2Fixture::IsSensor() const +{ + return m_isSensor; +} + +inline const b2Filter& b2Fixture::GetFilterData() const +{ + return m_filter; +} + +inline void* b2Fixture::GetUserData() const +{ + return m_userData; +} + +inline void b2Fixture::SetUserData(void* data) +{ + m_userData = data; +} + +inline b2Body* b2Fixture::GetBody() +{ + return m_body; +} + +inline const b2Body* b2Fixture::GetBody() const +{ + return m_body; +} + +inline b2Fixture* b2Fixture::GetNext() +{ + return m_next; +} + +inline const b2Fixture* b2Fixture::GetNext() const +{ + return m_next; +} + +inline void b2Fixture::SetDensity(float32 density) +{ + b2Assert(b2IsValid(density) && density >= 0.0f); + m_density = density; +} + +inline float32 b2Fixture::GetDensity() const +{ + return m_density; +} + +inline float32 b2Fixture::GetFriction() const +{ + return m_friction; +} + +inline void b2Fixture::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Fixture::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Fixture::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline bool b2Fixture::TestPoint(const b2Vec2& p) const +{ + return m_shape->TestPoint(m_body->GetTransform(), p); +} + +inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const +{ + return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); +} + +inline void b2Fixture::GetMassData(b2MassData* massData) const +{ + m_shape->ComputeMass(massData, m_density); +} + +inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const +{ + b2Assert(0 <= childIndex && childIndex < m_proxyCount); + return m_proxies[childIndex].aabb; +} + +#endif diff --git a/external/box2d/Dynamics/b2Island.cpp b/external/box2d/Dynamics/b2Island.cpp new file mode 100644 index 0000000000..e767d383d5 --- /dev/null +++ b/external/box2d/Dynamics/b2Island.cpp @@ -0,0 +1,539 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +Position Correction Notes +========================= +I tried the several algorithms for position correction of the 2D revolute joint. +I looked at these systems: +- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. +- suspension bridge with 30 1m long planks of length 1m. +- multi-link chain with 30 1m long links. + +Here are the algorithms: + +Baumgarte - A fraction of the position error is added to the velocity error. There is no +separate position solver. + +Pseudo Velocities - After the velocity solver and position integration, +the position error, Jacobian, and effective mass are recomputed. Then +the velocity constraints are solved with pseudo velocities and a fraction +of the position error is added to the pseudo velocity error. The pseudo +velocities are initialized to zero and there is no warm-starting. After +the position solver, the pseudo velocities are added to the positions. +This is also called the First Order World method or the Position LCP method. + +Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the +position error is re-computed for each constraint and the positions are updated +after the constraint is solved. The radius vectors (aka Jacobians) are +re-computed too (otherwise the algorithm has horrible instability). The pseudo +velocity states are not needed because they are effectively zero at the beginning +of each iteration. Since we have the current position error, we allow the +iterations to terminate early if the error becomes smaller than b2_linearSlop. + +Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed +each time a constraint is solved. + +Here are the results: +Baumgarte - this is the cheapest algorithm but it has some stability problems, +especially with the bridge. The chain links separate easily close to the root +and they jitter as they struggle to pull together. This is one of the most common +methods in the field. The big drawback is that the position correction artificially +affects the momentum, thus leading to instabilities and false bounce. I used a +bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller +factor makes joints and contacts more spongy. + +Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is +stable. However, joints still separate with large angular velocities. Drag the +simple pendulum in a circle quickly and the joint will separate. The chain separates +easily and does not recover. I used a bias factor of 0.2. A larger value lead to +the bridge collapsing when a heavy cube drops on it. + +Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo +Velocities, but in other ways it is worse. The bridge and chain are much more +stable, but the simple pendulum goes unstable at high angular velocities. + +Full NGS - stable in all tests. The joints display good stiffness. The bridge +still sags, but this is better than infinite forces. + +Recommendations +Pseudo Velocities are not really worthwhile because the bridge and chain cannot +recover from joint separation. In other cases the benefit over Baumgarte is small. + +Modified NGS is not a robust method for the revolute joint due to the violent +instability seen in the simple pendulum. Perhaps it is viable with other constraint +types, especially scalar constraints where the effective mass is a scalar. + +This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities +and is very fast. I don't think we can escape Baumgarte, especially in highly +demanding cases where high constraint fidelity is not needed. + +Full NGS is robust and easy on the eyes. I recommend this as an option for +higher fidelity simulation and certainly for suspension bridges and long chains. +Full NGS might be a good choice for ragdolls, especially motorized ragdolls where +joint separation can be problematic. The number of NGS iterations can be reduced +for better performance without harming robustness much. + +Each joint in a can be handled differently in the position solver. So I recommend +a system where the user can select the algorithm on a per joint basis. I would +probably default to the slower Full NGS and let the user select the faster +Baumgarte method in performance critical scenarios. +*/ + +/* +Cache Performance + +The Box2D solvers are dominated by cache misses. Data structures are designed +to increase the number of cache hits. Much of misses are due to random access +to body data. The constraint structures are iterated over linearly, which leads +to few cache misses. + +The bodies are not accessed during iteration. Instead read only data, such as +the mass values are stored with the constraints. The mutable data are the constraint +impulses and the bodies velocities/positions. The impulses are held inside the +constraint structures. The body velocities/positions are held in compact, temporary +arrays to increase the number of cache hits. Linear and angular velocity are +stored in a single array since multiple arrays lead to multiple misses. +*/ + +/* +2D Rotation + +R = [cos(theta) -sin(theta)] + [sin(theta) cos(theta) ] + +thetaDot = omega + +Let q1 = cos(theta), q2 = sin(theta). +R = [q1 -q2] + [q2 q1] + +q1Dot = -thetaDot * q2 +q2Dot = thetaDot * q1 + +q1_new = q1_old - dt * w * q2 +q2_new = q2_old + dt * w * q1 +then normalize. + +This might be faster than computing sin+cos. +However, we can compute sin+cos of the same angle fast. +*/ + +b2Island::b2Island( + int32 bodyCapacity, + int32 contactCapacity, + int32 jointCapacity, + b2StackAllocator* allocator, + b2ContactListener* listener) +{ + m_bodyCapacity = bodyCapacity; + m_contactCapacity = contactCapacity; + m_jointCapacity = jointCapacity; + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + + m_allocator = allocator; + m_listener = listener; + + m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); + m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); + m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); + + m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); + m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); +} + +b2Island::~b2Island() +{ + // Warning: the order should reverse the constructor order. + m_allocator->Free(m_positions); + m_allocator->Free(m_velocities); + m_allocator->Free(m_joints); + m_allocator->Free(m_contacts); + m_allocator->Free(m_bodies); +} + +void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) +{ + b2Timer timer; + + float32 h = step.dt; + + // Integrate velocities and apply damping. Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + + b2Vec2 c = b->m_sweep.c; + float32 a = b->m_sweep.a; + b2Vec2 v = b->m_linearVelocity; + float32 w = b->m_angularVelocity; + + // Store positions for continuous collision. + b->m_sweep.c0 = b->m_sweep.c; + b->m_sweep.a0 = b->m_sweep.a; + + if (b->m_type == b2_dynamicBody) + { + // Integrate velocities. + v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); + w += h * b->m_invI * b->m_torque; + + // Apply damping. + // ODE: dv/dt + c * v = 0 + // Solution: v(t) = v0 * exp(-c * t) + // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) + // v2 = exp(-c * dt) * v1 + // Taylor expansion: + // v2 = (1.0f - c * dt) * v1 + v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); + w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); + } + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + timer.Reset(); + + // Solver data + b2SolverData solverData; + solverData.step = step; + solverData.positions = m_positions; + solverData.velocities = m_velocities; + + // Initialize velocity constraints. + b2ContactSolverDef contactSolverDef; + contactSolverDef.step = step; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + contactSolverDef.allocator = m_allocator; + + b2ContactSolver contactSolver(&contactSolverDef); + contactSolver.InitializeVelocityConstraints(); + + if (step.warmStarting) + { + contactSolver.WarmStart(); + } + + for (int32 i = 0; i < m_jointCount; ++i) + { + m_joints[i]->InitVelocityConstraints(solverData); + } + + profile->solveInit = timer.GetMilliseconds(); + + // Solve velocity constraints + timer.Reset(); + for (int32 i = 0; i < step.velocityIterations; ++i) + { + for (int32 j = 0; j < m_jointCount; ++j) + { + m_joints[j]->SolveVelocityConstraints(solverData); + } + + contactSolver.SolveVelocityConstraints(); + } + + // Store impulses for warm starting + contactSolver.StoreImpulses(); + profile->solveVelocity = timer.GetMilliseconds(); + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + // Solve position constraints + timer.Reset(); + bool positionSolved = false; + for (int32 i = 0; i < step.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolvePositionConstraints(); + + bool jointsOkay = true; + for (int32 i = 0; i < m_jointCount; ++i) + { + bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); + jointsOkay = jointsOkay && jointOkay; + } + + if (contactsOkay && jointsOkay) + { + // Exit early if the position errors are small. + positionSolved = true; + break; + } + } + + // Copy state buffers back to the bodies + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* body = m_bodies[i]; + body->m_sweep.c = m_positions[i].c; + body->m_sweep.a = m_positions[i].a; + body->m_linearVelocity = m_velocities[i].v; + body->m_angularVelocity = m_velocities[i].w; + body->SynchronizeTransform(); + } + + profile->solvePosition = timer.GetMilliseconds(); + + Report(contactSolver.m_velocityConstraints); + + if (allowSleep) + { + float32 minSleepTime = b2_maxFloat; + + const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; + const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; + + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + continue; + } + + if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || + b->m_angularVelocity * b->m_angularVelocity > angTolSqr || + b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) + { + b->m_sleepTime = 0.0f; + minSleepTime = 0.0f; + } + else + { + b->m_sleepTime += h; + minSleepTime = b2Min(minSleepTime, b->m_sleepTime); + } + } + + if (minSleepTime >= b2_timeToSleep && positionSolved) + { + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + b->SetAwake(false); + } + } + } +} + +void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) +{ + b2Assert(toiIndexA < m_bodyCount); + b2Assert(toiIndexB < m_bodyCount); + + // Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + m_positions[i].c = b->m_sweep.c; + m_positions[i].a = b->m_sweep.a; + m_velocities[i].v = b->m_linearVelocity; + m_velocities[i].w = b->m_angularVelocity; + } + + b2ContactSolverDef contactSolverDef; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.allocator = m_allocator; + contactSolverDef.step = subStep; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + b2ContactSolver contactSolver(&contactSolverDef); + + // Solve position constraints. + for (int32 i = 0; i < subStep.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); + if (contactsOkay) + { + break; + } + } + +#if 0 + // Is the new position really safe? + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + b2DistanceInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.transformA = bA->GetTransform(); + input.transformB = bB->GetTransform(); + input.useRadii = false; + + b2DistanceOutput output; + b2SimplexCache cache; + cache.count = 0; + b2Distance(&output, &cache, &input); + + if (output.distance == 0 || cache.count == 3) + { + cache.count += 0; + } + } +#endif + + // Leap of faith to new safe state. + m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; + m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; + m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; + m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; + + // No warm starting is needed for TOI events because warm + // starting impulses were applied in the discrete solver. + contactSolver.InitializeVelocityConstraints(); + + // Solve velocity constraints. + for (int32 i = 0; i < subStep.velocityIterations; ++i) + { + contactSolver.SolveVelocityConstraints(); + } + + // Don't store the TOI contact forces for warm starting + // because they can be quite large. + + float32 h = subStep.dt; + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + + // Sync bodies + b2Body* body = m_bodies[i]; + body->m_sweep.c = c; + body->m_sweep.a = a; + body->m_linearVelocity = v; + body->m_angularVelocity = w; + body->SynchronizeTransform(); + } + + Report(contactSolver.m_velocityConstraints); +} + +void b2Island::Report(const b2ContactVelocityConstraint* constraints) +{ + if (m_listener == NULL) + { + return; + } + + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + + const b2ContactVelocityConstraint* vc = constraints + i; + + b2ContactImpulse impulse; + impulse.count = vc->pointCount; + for (int32 j = 0; j < vc->pointCount; ++j) + { + impulse.normalImpulses[j] = vc->points[j].normalImpulse; + impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; + } + + m_listener->PostSolve(c, &impulse); + } +} diff --git a/external/box2d/Dynamics/b2Island.h b/external/box2d/Dynamics/b2Island.h new file mode 100644 index 0000000000..e0a6e41fc3 --- /dev/null +++ b/external/box2d/Dynamics/b2Island.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_ISLAND_H +#define B2_ISLAND_H + +#include +#include +#include + +class b2Contact; +class b2Joint; +class b2StackAllocator; +class b2ContactListener; +struct b2ContactVelocityConstraint; +struct b2Profile; + +/// This is an internal class. +class b2Island +{ +public: + b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, + b2StackAllocator* allocator, b2ContactListener* listener); + ~b2Island(); + + void Clear() + { + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + } + + void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); + + void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); + + void Add(b2Body* body) + { + b2Assert(m_bodyCount < m_bodyCapacity); + body->m_islandIndex = m_bodyCount; + m_bodies[m_bodyCount] = body; + ++m_bodyCount; + } + + void Add(b2Contact* contact) + { + b2Assert(m_contactCount < m_contactCapacity); + m_contacts[m_contactCount++] = contact; + } + + void Add(b2Joint* joint) + { + b2Assert(m_jointCount < m_jointCapacity); + m_joints[m_jointCount++] = joint; + } + + void Report(const b2ContactVelocityConstraint* constraints); + + b2StackAllocator* m_allocator; + b2ContactListener* m_listener; + + b2Body** m_bodies; + b2Contact** m_contacts; + b2Joint** m_joints; + + b2Position* m_positions; + b2Velocity* m_velocities; + + int32 m_bodyCount; + int32 m_jointCount; + int32 m_contactCount; + + int32 m_bodyCapacity; + int32 m_contactCapacity; + int32 m_jointCapacity; +}; + +#endif diff --git a/external/box2d/Dynamics/b2TimeStep.h b/external/box2d/Dynamics/b2TimeStep.h new file mode 100644 index 0000000000..30d723fcc3 --- /dev/null +++ b/external/box2d/Dynamics/b2TimeStep.h @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_TIME_STEP_H +#define B2_TIME_STEP_H + +#include + +/// Profiling data. Times are in milliseconds. +struct b2Profile +{ + float32 step; + float32 collide; + float32 solve; + float32 solveInit; + float32 solveVelocity; + float32 solvePosition; + float32 broadphase; + float32 solveTOI; +}; + +/// This is an internal structure. +struct b2TimeStep +{ + float32 dt; // time step + float32 inv_dt; // inverse time step (0 if dt == 0). + float32 dtRatio; // dt * inv_dt0 + int32 velocityIterations; + int32 positionIterations; + bool warmStarting; +}; + +/// This is an internal structure. +struct b2Position +{ + b2Vec2 c; + float32 a; +}; + +/// This is an internal structure. +struct b2Velocity +{ + b2Vec2 v; + float32 w; +}; + +/// Solver Data +struct b2SolverData +{ + b2TimeStep step; + b2Position* positions; + b2Velocity* velocities; +}; + +#endif diff --git a/external/box2d/Dynamics/b2World.cpp b/external/box2d/Dynamics/b2World.cpp new file mode 100644 index 0000000000..8a0aff5114 --- /dev/null +++ b/external/box2d/Dynamics/b2World.cpp @@ -0,0 +1,1316 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2World::b2World(const b2Vec2& gravity) +{ + m_destructionListener = NULL; + m_debugDraw = NULL; + + m_bodyList = NULL; + m_jointList = NULL; + + m_bodyCount = 0; + m_jointCount = 0; + + m_warmStarting = true; + m_continuousPhysics = true; + m_subStepping = false; + + m_stepComplete = true; + + m_allowSleep = true; + m_gravity = gravity; + + m_flags = e_clearForces; + + m_inv_dt0 = 0.0f; + + m_contactManager.m_allocator = &m_blockAllocator; + + memset(&m_profile, 0, sizeof(b2Profile)); +} + +b2World::~b2World() +{ + // Some shapes allocate using b2Alloc. + b2Body* b = m_bodyList; + while (b) + { + b2Body* bNext = b->m_next; + + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* fNext = f->m_next; + f->m_proxyCount = 0; + f->Destroy(&m_blockAllocator); + f = fNext; + } + + b = bNext; + } +} + +void b2World::SetDestructionListener(b2DestructionListener* listener) +{ + m_destructionListener = listener; +} + +void b2World::SetContactFilter(b2ContactFilter* filter) +{ + m_contactManager.m_contactFilter = filter; +} + +void b2World::SetContactListener(b2ContactListener* listener) +{ + m_contactManager.m_contactListener = listener; +} + +void b2World::SetDebugDraw(b2Draw* debugDraw) +{ + m_debugDraw = debugDraw; +} + +b2Body* b2World::CreateBody(const b2BodyDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); + b2Body* b = new (mem) b2Body(def, this); + + // Add to world doubly linked list. + b->m_prev = NULL; + b->m_next = m_bodyList; + if (m_bodyList) + { + m_bodyList->m_prev = b; + } + m_bodyList = b; + ++m_bodyCount; + + return b; +} + +void b2World::DestroyBody(b2Body* b) +{ + b2Assert(m_bodyCount > 0); + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + // Delete the attached joints. + b2JointEdge* je = b->m_jointList; + while (je) + { + b2JointEdge* je0 = je; + je = je->next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(je0->joint); + } + + DestroyJoint(je0->joint); + + b->m_jointList = je; + } + b->m_jointList = NULL; + + // Delete the attached contacts. + b2ContactEdge* ce = b->m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_contactManager.Destroy(ce0->contact); + } + b->m_contactList = NULL; + + // Delete the attached fixtures. This destroys broad-phase proxies. + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* f0 = f; + f = f->m_next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(f0); + } + + f0->DestroyProxies(&m_contactManager.m_broadPhase); + f0->Destroy(&m_blockAllocator); + f0->~b2Fixture(); + m_blockAllocator.Free(f0, sizeof(b2Fixture)); + + b->m_fixtureList = f; + b->m_fixtureCount -= 1; + } + b->m_fixtureList = NULL; + b->m_fixtureCount = 0; + + // Remove world body list. + if (b->m_prev) + { + b->m_prev->m_next = b->m_next; + } + + if (b->m_next) + { + b->m_next->m_prev = b->m_prev; + } + + if (b == m_bodyList) + { + m_bodyList = b->m_next; + } + + --m_bodyCount; + b->~b2Body(); + m_blockAllocator.Free(b, sizeof(b2Body)); +} + +b2Joint* b2World::CreateJoint(const b2JointDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + b2Joint* j = b2Joint::Create(def, &m_blockAllocator); + + // Connect to the world list. + j->m_prev = NULL; + j->m_next = m_jointList; + if (m_jointList) + { + m_jointList->m_prev = j; + } + m_jointList = j; + ++m_jointCount; + + // Connect to the bodies' doubly linked lists. + j->m_edgeA.joint = j; + j->m_edgeA.other = j->m_bodyB; + j->m_edgeA.prev = NULL; + j->m_edgeA.next = j->m_bodyA->m_jointList; + if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; + j->m_bodyA->m_jointList = &j->m_edgeA; + + j->m_edgeB.joint = j; + j->m_edgeB.other = j->m_bodyA; + j->m_edgeB.prev = NULL; + j->m_edgeB.next = j->m_bodyB->m_jointList; + if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; + j->m_bodyB->m_jointList = &j->m_edgeB; + + b2Body* bodyA = def->bodyA; + b2Body* bodyB = def->bodyB; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (def->collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } + + // Note: creating a joint doesn't wake the bodies. + + return j; +} + +void b2World::DestroyJoint(b2Joint* j) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + bool collideConnected = j->m_collideConnected; + + // Remove from the doubly linked list. + if (j->m_prev) + { + j->m_prev->m_next = j->m_next; + } + + if (j->m_next) + { + j->m_next->m_prev = j->m_prev; + } + + if (j == m_jointList) + { + m_jointList = j->m_next; + } + + // Disconnect from island graph. + b2Body* bodyA = j->m_bodyA; + b2Body* bodyB = j->m_bodyB; + + // Wake up connected bodies. + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + // Remove from body 1. + if (j->m_edgeA.prev) + { + j->m_edgeA.prev->next = j->m_edgeA.next; + } + + if (j->m_edgeA.next) + { + j->m_edgeA.next->prev = j->m_edgeA.prev; + } + + if (&j->m_edgeA == bodyA->m_jointList) + { + bodyA->m_jointList = j->m_edgeA.next; + } + + j->m_edgeA.prev = NULL; + j->m_edgeA.next = NULL; + + // Remove from body 2 + if (j->m_edgeB.prev) + { + j->m_edgeB.prev->next = j->m_edgeB.next; + } + + if (j->m_edgeB.next) + { + j->m_edgeB.next->prev = j->m_edgeB.prev; + } + + if (&j->m_edgeB == bodyB->m_jointList) + { + bodyB->m_jointList = j->m_edgeB.next; + } + + j->m_edgeB.prev = NULL; + j->m_edgeB.next = NULL; + + b2Joint::Destroy(j, &m_blockAllocator); + + b2Assert(m_jointCount > 0); + --m_jointCount; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } +} + +// +void b2World::SetAllowSleeping(bool flag) +{ + if (flag == m_allowSleep) + { + return; + } + + m_allowSleep = flag; + if (m_allowSleep == false) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->SetAwake(true); + } + } +} + +// Find islands, integrate and solve constraints, solve position constraints +void b2World::Solve(const b2TimeStep& step) +{ + m_profile.solveInit = 0.0f; + m_profile.solveVelocity = 0.0f; + m_profile.solvePosition = 0.0f; + + // Size the island for the worst case. + b2Island island(m_bodyCount, + m_contactManager.m_contactCount, + m_jointCount, + &m_stackAllocator, + m_contactManager.m_contactListener); + + // Clear all the island flags. + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + c->m_flags &= ~b2Contact::e_islandFlag; + } + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_islandFlag = false; + } + + // Build and simulate all awake islands. + int32 stackSize = m_bodyCount; + b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); + for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) + { + if (seed->m_flags & b2Body::e_islandFlag) + { + continue; + } + + if (seed->IsAwake() == false || seed->IsActive() == false) + { + continue; + } + + // The seed can be dynamic or kinematic. + if (seed->GetType() == b2_staticBody) + { + continue; + } + + // Reset island and stack. + island.Clear(); + int32 stackCount = 0; + stack[stackCount++] = seed; + seed->m_flags |= b2Body::e_islandFlag; + + // Perform a depth first search (DFS) on the constraint graph. + while (stackCount > 0) + { + // Grab the next body off the stack and add it to the island. + b2Body* b = stack[--stackCount]; + b2Assert(b->IsActive() == true); + island.Add(b); + + // Make sure the body is awake. + b->SetAwake(true); + + // To keep islands as small as possible, we don't + // propagate islands across static bodies. + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Search all contacts connected to this body. + for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) + { + b2Contact* contact = ce->contact; + + // Has this contact already been added to an island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Is this contact solid and touching? + if (contact->IsEnabled() == false || + contact->IsTouching() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + island.Add(contact); + contact->m_flags |= b2Contact::e_islandFlag; + + b2Body* other = ce->other; + + // Was the other body already added to this island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + + // Search all joints connect to this body. + for (b2JointEdge* je = b->m_jointList; je; je = je->next) + { + if (je->joint->m_islandFlag == true) + { + continue; + } + + b2Body* other = je->other; + + // Don't simulate joints connected to inactive bodies. + if (other->IsActive() == false) + { + continue; + } + + island.Add(je->joint); + je->joint->m_islandFlag = true; + + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + } + + b2Profile profile; + island.Solve(&profile, step, m_gravity, m_allowSleep); + m_profile.solveInit += profile.solveInit; + m_profile.solveVelocity += profile.solveVelocity; + m_profile.solvePosition += profile.solvePosition; + + // Post solve cleanup. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + // Allow static bodies to participate in other islands. + b2Body* b = island.m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + } + } + + m_stackAllocator.Free(stack); + + { + b2Timer timer; + // Synchronize fixtures, check for out of range bodies. + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + // If a body was not in an island then it did not move. + if ((b->m_flags & b2Body::e_islandFlag) == 0) + { + continue; + } + + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Update fixtures (for broad-phase). + b->SynchronizeFixtures(); + } + + // Look for new contacts. + m_contactManager.FindNewContacts(); + m_profile.broadphase = timer.GetMilliseconds(); + } +} + +// Find TOI contacts and solve them. +void b2World::SolveTOI(const b2TimeStep& step) +{ + b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); + + if (m_stepComplete) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + b->m_sweep.alpha0 = 0.0f; + } + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Invalidate TOI + c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + c->m_toiCount = 0; + c->m_toi = 1.0f; + } + } + + // Find TOI events and solve them. + for (;;) + { + // Find the first TOI. + b2Contact* minContact = NULL; + float32 minAlpha = 1.0f; + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Is this contact disabled? + if (c->IsEnabled() == false) + { + continue; + } + + // Prevent excessive sub-stepping. + if (c->m_toiCount > b2_maxSubSteps) + { + continue; + } + + float32 alpha = 1.0f; + if (c->m_flags & b2Contact::e_toiFlag) + { + // This contact has a valid cached TOI. + alpha = c->m_toi; + } + else + { + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + // Is there a sensor? + if (fA->IsSensor() || fB->IsSensor()) + { + continue; + } + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2BodyType typeA = bA->m_type; + b2BodyType typeB = bB->m_type; + b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); + + bool activeA = bA->IsAwake() && typeA != b2_staticBody; + bool activeB = bB->IsAwake() && typeB != b2_staticBody; + + // Is at least one body active (awake and dynamic or kinematic)? + if (activeA == false && activeB == false) + { + continue; + } + + bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; + bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; + + // Are these two non-bullet dynamic bodies? + if (collideA == false && collideB == false) + { + continue; + } + + // Compute the TOI for this contact. + // Put the sweeps onto the same time interval. + float32 alpha0 = bA->m_sweep.alpha0; + + if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) + { + alpha0 = bB->m_sweep.alpha0; + bA->m_sweep.Advance(alpha0); + } + else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) + { + alpha0 = bA->m_sweep.alpha0; + bB->m_sweep.Advance(alpha0); + } + + b2Assert(alpha0 < 1.0f); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + // Compute the time of impact in interval [0, minTOI] + b2TOIInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.sweepA = bA->m_sweep; + input.sweepB = bB->m_sweep; + input.tMax = 1.0f; + + b2TOIOutput output; + b2TimeOfImpact(&output, &input); + + // Beta is the fraction of the remaining portion of the . + float32 beta = output.t; + if (output.state == b2TOIOutput::e_touching) + { + alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); + } + else + { + alpha = 1.0f; + } + + c->m_toi = alpha; + c->m_flags |= b2Contact::e_toiFlag; + } + + if (alpha < minAlpha) + { + // This is the minimum TOI found so far. + minContact = c; + minAlpha = alpha; + } + } + + if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) + { + // No more TOI events. Done! + m_stepComplete = true; + break; + } + + // Advance the bodies to the TOI. + b2Fixture* fA = minContact->GetFixtureA(); + b2Fixture* fB = minContact->GetFixtureB(); + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2Sweep backup1 = bA->m_sweep; + b2Sweep backup2 = bB->m_sweep; + + bA->Advance(minAlpha); + bB->Advance(minAlpha); + + // The TOI contact likely has some new contact points. + minContact->Update(m_contactManager.m_contactListener); + minContact->m_flags &= ~b2Contact::e_toiFlag; + ++minContact->m_toiCount; + + // Is the contact solid? + if (minContact->IsEnabled() == false || minContact->IsTouching() == false) + { + // Restore the sweeps. + minContact->SetEnabled(false); + bA->m_sweep = backup1; + bB->m_sweep = backup2; + bA->SynchronizeTransform(); + bB->SynchronizeTransform(); + continue; + } + + bA->SetAwake(true); + bB->SetAwake(true); + + // Build the island + island.Clear(); + island.Add(bA); + island.Add(bB); + island.Add(minContact); + + bA->m_flags |= b2Body::e_islandFlag; + bB->m_flags |= b2Body::e_islandFlag; + minContact->m_flags |= b2Contact::e_islandFlag; + + // Get contacts on bodyA and bodyB. + b2Body* bodies[2] = {bA, bB}; + for (int32 i = 0; i < 2; ++i) + { + b2Body* body = bodies[i]; + if (body->m_type == b2_dynamicBody) + { + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + if (island.m_bodyCount == island.m_bodyCapacity) + { + break; + } + + if (island.m_contactCount == island.m_contactCapacity) + { + break; + } + + b2Contact* contact = ce->contact; + + // Has this contact already been added to the island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Only add static, kinematic, or bullet bodies. + b2Body* other = ce->other; + if (other->m_type == b2_dynamicBody && + body->IsBullet() == false && other->IsBullet() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + // Tentatively advance the body to the TOI. + b2Sweep backup = other->m_sweep; + if ((other->m_flags & b2Body::e_islandFlag) == 0) + { + other->Advance(minAlpha); + } + + // Update the contact points + contact->Update(m_contactManager.m_contactListener); + + // Was the contact disabled by the user? + if (contact->IsEnabled() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Are there contact points? + if (contact->IsTouching() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Add the contact to the island + contact->m_flags |= b2Contact::e_islandFlag; + island.Add(contact); + + // Has the other body already been added to the island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + // Add the other body to the island. + other->m_flags |= b2Body::e_islandFlag; + + if (other->m_type != b2_staticBody) + { + other->SetAwake(true); + } + + island.Add(other); + } + } + } + + b2TimeStep subStep; + subStep.dt = (1.0f - minAlpha) * step.dt; + subStep.inv_dt = 1.0f / subStep.dt; + subStep.dtRatio = 1.0f; + subStep.positionIterations = 20; + subStep.velocityIterations = step.velocityIterations; + subStep.warmStarting = false; + island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); + + // Reset island flags and synchronize broad-phase proxies. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + b2Body* body = island.m_bodies[i]; + body->m_flags &= ~b2Body::e_islandFlag; + + if (body->m_type != b2_dynamicBody) + { + continue; + } + + body->SynchronizeFixtures(); + + // Invalidate all contact TOIs on this displaced body. + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + } + } + + // Commit fixture proxy movements to the broad-phase so that new contacts are created. + // Also, some contacts can be destroyed. + m_contactManager.FindNewContacts(); + + if (m_subStepping) + { + m_stepComplete = false; + break; + } + } +} + +void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) +{ + b2Timer stepTimer; + + // If new fixtures were added, we need to find the new contacts. + if (m_flags & e_newFixture) + { + m_contactManager.FindNewContacts(); + m_flags &= ~e_newFixture; + } + + m_flags |= e_locked; + + b2TimeStep step; + step.dt = dt; + step.velocityIterations = velocityIterations; + step.positionIterations = positionIterations; + if (dt > 0.0f) + { + step.inv_dt = 1.0f / dt; + } + else + { + step.inv_dt = 0.0f; + } + + step.dtRatio = m_inv_dt0 * dt; + + step.warmStarting = m_warmStarting; + + // Update contacts. This is where some contacts are destroyed. + { + b2Timer timer; + m_contactManager.Collide(); + m_profile.collide = timer.GetMilliseconds(); + } + + // Integrate velocities, solve velocity constraints, and integrate positions. + if (m_stepComplete && step.dt > 0.0f) + { + b2Timer timer; + Solve(step); + m_profile.solve = timer.GetMilliseconds(); + } + + // Handle TOI events. + if (m_continuousPhysics && step.dt > 0.0f) + { + b2Timer timer; + SolveTOI(step); + m_profile.solveTOI = timer.GetMilliseconds(); + } + + if (step.dt > 0.0f) + { + m_inv_dt0 = step.inv_dt; + } + + if (m_flags & e_clearForces) + { + ClearForces(); + } + + m_flags &= ~e_locked; + + m_profile.step = stepTimer.GetMilliseconds(); +} + +void b2World::ClearForces() +{ + for (b2Body* body = m_bodyList; body; body = body->GetNext()) + { + body->m_force.SetZero(); + body->m_torque = 0.0f; + } +} + +struct b2WorldQueryWrapper +{ + bool QueryCallback(int32 proxyId) + { + b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); + return callback->ReportFixture(proxy->fixture); + } + + const b2BroadPhase* broadPhase; + b2QueryCallback* callback; +}; + +void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const +{ + b2WorldQueryWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + m_contactManager.m_broadPhase.Query(&wrapper, aabb); +} + +struct b2WorldRayCastWrapper +{ + float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) + { + void* userData = broadPhase->GetUserData(proxyId); + b2FixtureProxy* proxy = (b2FixtureProxy*)userData; + b2Fixture* fixture = proxy->fixture; + int32 index = proxy->childIndex; + b2RayCastOutput output; + bool hit = fixture->RayCast(&output, input, index); + + if (hit) + { + float32 fraction = output.fraction; + b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; + return callback->ReportFixture(fixture, point, output.normal, fraction); + } + + return input.maxFraction; + } + + const b2BroadPhase* broadPhase; + b2RayCastCallback* callback; +}; + +void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const +{ + b2WorldRayCastWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + b2RayCastInput input; + input.maxFraction = 1.0f; + input.p1 = point1; + input.p2 = point2; + m_contactManager.m_broadPhase.RayCast(&wrapper, input); +} + +void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) +{ + switch (fixture->GetType()) + { + case b2Shape::e_circle: + { + b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); + + b2Vec2 center = b2Mul(xf, circle->m_p); + float32 radius = circle->m_radius; + b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); + + m_debugDraw->DrawSolidCircle(center, radius, axis, color); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); + b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); + b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); + m_debugDraw->DrawSegment(v1, v2, color); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); + int32 count = chain->m_count; + const b2Vec2* vertices = chain->m_vertices; + + b2Vec2 v1 = b2Mul(xf, vertices[0]); + for (int32 i = 1; i < count; ++i) + { + b2Vec2 v2 = b2Mul(xf, vertices[i]); + m_debugDraw->DrawSegment(v1, v2, color); + m_debugDraw->DrawCircle(v1, 0.05f, color); + v1 = v2; + } + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); + int32 vertexCount = poly->m_vertexCount; + b2Assert(vertexCount <= b2_maxPolygonVertices); + b2Vec2 vertices[b2_maxPolygonVertices]; + + for (int32 i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Mul(xf, poly->m_vertices[i]); + } + + m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); + } + break; + + default: + break; + } +} + +void b2World::DrawJoint(b2Joint* joint) +{ + b2Body* bodyA = joint->GetBodyA(); + b2Body* bodyB = joint->GetBodyB(); + const b2Transform& xf1 = bodyA->GetTransform(); + const b2Transform& xf2 = bodyB->GetTransform(); + b2Vec2 x1 = xf1.p; + b2Vec2 x2 = xf2.p; + b2Vec2 p1 = joint->GetAnchorA(); + b2Vec2 p2 = joint->GetAnchorB(); + + b2Color color(0.5f, 0.8f, 0.8f); + + switch (joint->GetType()) + { + case e_distanceJoint: + m_debugDraw->DrawSegment(p1, p2, color); + break; + + case e_pulleyJoint: + { + b2PulleyJoint* pulley = (b2PulleyJoint*)joint; + b2Vec2 s1 = pulley->GetGroundAnchorA(); + b2Vec2 s2 = pulley->GetGroundAnchorB(); + m_debugDraw->DrawSegment(s1, p1, color); + m_debugDraw->DrawSegment(s2, p2, color); + m_debugDraw->DrawSegment(s1, s2, color); + } + break; + + case e_mouseJoint: + // don't draw this + break; + + default: + m_debugDraw->DrawSegment(x1, p1, color); + m_debugDraw->DrawSegment(p1, p2, color); + m_debugDraw->DrawSegment(x2, p2, color); + } +} + +void b2World::DrawDebugData() +{ + if (m_debugDraw == NULL) + { + return; + } + + uint32 flags = m_debugDraw->GetFlags(); + + if (flags & b2Draw::e_shapeBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + const b2Transform& xf = b->GetTransform(); + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + if (b->IsActive() == false) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); + } + else if (b->GetType() == b2_staticBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); + } + else if (b->GetType() == b2_kinematicBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); + } + else if (b->IsAwake() == false) + { + DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); + } + else + { + DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); + } + } + } + } + + if (flags & b2Draw::e_jointBit) + { + for (b2Joint* j = m_jointList; j; j = j->GetNext()) + { + DrawJoint(j); + } + } + + if (flags & b2Draw::e_pairBit) + { + b2Color color(0.3f, 0.9f, 0.9f); + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) + { + //b2Fixture* fixtureA = c->GetFixtureA(); + //b2Fixture* fixtureB = c->GetFixtureB(); + + //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); + //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); + + //m_debugDraw->DrawSegment(cA, cB, color); + } + } + + if (flags & b2Draw::e_aabbBit) + { + b2Color color(0.9f, 0.3f, 0.9f); + b2BroadPhase* bp = &m_contactManager.m_broadPhase; + + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + if (b->IsActive() == false) + { + continue; + } + + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + for (int32 i = 0; i < f->m_proxyCount; ++i) + { + b2FixtureProxy* proxy = f->m_proxies + i; + b2AABB aabb = bp->GetFatAABB(proxy->proxyId); + b2Vec2 vs[4]; + vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); + vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); + vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); + vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); + + m_debugDraw->DrawPolygon(vs, 4, color); + } + } + } + } + + if (flags & b2Draw::e_centerOfMassBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + b2Transform xf = b->GetTransform(); + xf.p = b->GetWorldCenter(); + m_debugDraw->DrawTransform(xf); + } + } +} + +int32 b2World::GetProxyCount() const +{ + return m_contactManager.m_broadPhase.GetProxyCount(); +} + +int32 b2World::GetTreeHeight() const +{ + return m_contactManager.m_broadPhase.GetTreeHeight(); +} + +int32 b2World::GetTreeBalance() const +{ + return m_contactManager.m_broadPhase.GetTreeBalance(); +} + +float32 b2World::GetTreeQuality() const +{ + return m_contactManager.m_broadPhase.GetTreeQuality(); +} + +void b2World::Dump() +{ + if ((m_flags & e_locked) == e_locked) + { + return; + } + + b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); + b2Log("m_world->SetGravity(g);\n"); + + b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); + b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); + int32 i = 0; + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_islandIndex = i; + b->Dump(); + ++i; + } + + i = 0; + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_index = i; + ++i; + } + + // First pass on joints, skip gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type == e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + // Second pass on joints, only gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type != e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + b2Log("b2Free(joints);\n"); + b2Log("b2Free(bodies);\n"); + b2Log("joints = NULL;\n"); + b2Log("bodies = NULL;\n"); +} diff --git a/external/box2d/Dynamics/b2World.h b/external/box2d/Dynamics/b2World.h new file mode 100644 index 0000000000..f207930511 --- /dev/null +++ b/external/box2d/Dynamics/b2World.h @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WORLD_H +#define B2_WORLD_H + +#include +#include +#include +#include +#include +#include + +struct b2AABB; +struct b2BodyDef; +struct b2Color; +struct b2JointDef; +class b2Body; +class b2Draw; +class b2Fixture; +class b2Joint; + +/// The world class manages all physics entities, dynamic simulation, +/// and asynchronous queries. The world also contains efficient memory +/// management facilities. +class b2World +{ +public: + /// Construct a world object. + /// @param gravity the world gravity vector. + b2World(const b2Vec2& gravity); + + /// Destruct the world. All physics entities are destroyed and all heap memory is released. + ~b2World(); + + /// Register a destruction listener. The listener is owned by you and must + /// remain in scope. + void SetDestructionListener(b2DestructionListener* listener); + + /// Register a contact filter to provide specific control over collision. + /// Otherwise the default filter is used (b2_defaultFilter). The listener is + /// owned by you and must remain in scope. + void SetContactFilter(b2ContactFilter* filter); + + /// Register a contact event listener. The listener is owned by you and must + /// remain in scope. + void SetContactListener(b2ContactListener* listener); + + /// Register a routine for debug drawing. The debug draw functions are called + /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// by you and must remain in scope. + void SetDebugDraw(b2Draw* debugDraw); + + /// Create a rigid body given a definition. No reference to the definition + /// is retained. + /// @warning This function is locked during callbacks. + b2Body* CreateBody(const b2BodyDef* def); + + /// Destroy a rigid body given a definition. No reference to the definition + /// is retained. This function is locked during callbacks. + /// @warning This automatically deletes all associated shapes and joints. + /// @warning This function is locked during callbacks. + void DestroyBody(b2Body* body); + + /// Create a joint to constrain bodies together. No reference to the definition + /// is retained. This may cause the connected bodies to cease colliding. + /// @warning This function is locked during callbacks. + b2Joint* CreateJoint(const b2JointDef* def); + + /// Destroy a joint. This may cause the connected bodies to begin colliding. + /// @warning This function is locked during callbacks. + void DestroyJoint(b2Joint* joint); + + /// Take a time step. This performs collision detection, integration, + /// and constraint solution. + /// @param timeStep the amount of time to simulate, this should not vary. + /// @param velocityIterations for the velocity constraint solver. + /// @param positionIterations for the position constraint solver. + void Step( float32 timeStep, + int32 velocityIterations, + int32 positionIterations); + + /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically + /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. + /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain + /// a fixed sized time step under a variable frame-rate. + /// When you perform sub-stepping you will disable auto clearing of forces and instead call + /// ClearForces after all sub-steps are complete in one pass of your game loop. + /// @see SetAutoClearForces + void ClearForces(); + + /// Call this to draw shapes and other debug draw data. + void DrawDebugData(); + + /// Query the world for all fixtures that potentially overlap the + /// provided AABB. + /// @param callback a user implemented callback class. + /// @param aabb the query box. + void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; + + /// Ray-cast the world for all fixtures in the path of the ray. Your callback + /// controls whether you get the closest point, any point, or n-points. + /// The ray-cast ignores shapes that contain the starting point. + /// @param callback a user implemented callback class. + /// @param point1 the ray starting point + /// @param point2 the ray ending point + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + + /// Get the world body list. With the returned body, use b2Body::GetNext to get + /// the next body in the world list. A NULL body indicates the end of the list. + /// @return the head of the world body list. + b2Body* GetBodyList(); + const b2Body* GetBodyList() const; + + /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get + /// the next joint in the world list. A NULL joint indicates the end of the list. + /// @return the head of the world joint list. + b2Joint* GetJointList(); + const b2Joint* GetJointList() const; + + /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get + /// the next contact in the world list. A NULL contact indicates the end of the list. + /// @return the head of the world contact list. + /// @warning contacts are created and destroyed in the middle of a time step. + /// Use b2ContactListener to avoid missing contacts. + b2Contact* GetContactList(); + const b2Contact* GetContactList() const; + + /// Enable/disable sleep. + void SetAllowSleeping(bool flag); + bool GetAllowSleeping() const { return m_allowSleep; } + + /// Enable/disable warm starting. For testing. + void SetWarmStarting(bool flag) { m_warmStarting = flag; } + bool GetWarmStarting() const { return m_warmStarting; } + + /// Enable/disable continuous physics. For testing. + void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } + bool GetContinuousPhysics() const { return m_continuousPhysics; } + + /// Enable/disable single stepped continuous physics. For testing. + void SetSubStepping(bool flag) { m_subStepping = flag; } + bool GetSubStepping() const { return m_subStepping; } + + /// Get the number of broad-phase proxies. + int32 GetProxyCount() const; + + /// Get the number of bodies. + int32 GetBodyCount() const; + + /// Get the number of joints. + int32 GetJointCount() const; + + /// Get the number of contacts (each may have 0 or more contact points). + int32 GetContactCount() const; + + /// Get the height of the dynamic tree. + int32 GetTreeHeight() const; + + /// Get the balance of the dynamic tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the dynamic tree. The smaller the better. + /// The minimum is 1. + float32 GetTreeQuality() const; + + /// Change the global gravity vector. + void SetGravity(const b2Vec2& gravity); + + /// Get the global gravity vector. + b2Vec2 GetGravity() const; + + /// Is the world locked (in the middle of a time step). + bool IsLocked() const; + + /// Set flag to control automatic clearing of forces after each time step. + void SetAutoClearForces(bool flag); + + /// Get the flag that controls automatic clearing of forces after each time step. + bool GetAutoClearForces() const; + + /// Get the contact manager for testing. + const b2ContactManager& GetContactManager() const; + + /// Get the current profile. + const b2Profile& GetProfile() const; + + /// Dump the world into the log file. + /// @warning this should be called outside of a time step. + void Dump(); + +private: + + // m_flags + enum + { + e_newFixture = 0x0001, + e_locked = 0x0002, + e_clearForces = 0x0004 + }; + + friend class b2Body; + friend class b2Fixture; + friend class b2ContactManager; + friend class b2Controller; + + void Solve(const b2TimeStep& step); + void SolveTOI(const b2TimeStep& step); + + void DrawJoint(b2Joint* joint); + void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); + + b2BlockAllocator m_blockAllocator; + b2StackAllocator m_stackAllocator; + + int32 m_flags; + + b2ContactManager m_contactManager; + + b2Body* m_bodyList; + b2Joint* m_jointList; + + int32 m_bodyCount; + int32 m_jointCount; + + b2Vec2 m_gravity; + bool m_allowSleep; + + b2DestructionListener* m_destructionListener; + b2Draw* m_debugDraw; + + // This is used to compute the time step ratio to + // support a variable time step. + float32 m_inv_dt0; + + // These are for debugging the solver. + bool m_warmStarting; + bool m_continuousPhysics; + bool m_subStepping; + + bool m_stepComplete; + + b2Profile m_profile; +}; + +inline b2Body* b2World::GetBodyList() +{ + return m_bodyList; +} + +inline const b2Body* b2World::GetBodyList() const +{ + return m_bodyList; +} + +inline b2Joint* b2World::GetJointList() +{ + return m_jointList; +} + +inline const b2Joint* b2World::GetJointList() const +{ + return m_jointList; +} + +inline b2Contact* b2World::GetContactList() +{ + return m_contactManager.m_contactList; +} + +inline const b2Contact* b2World::GetContactList() const +{ + return m_contactManager.m_contactList; +} + +inline int32 b2World::GetBodyCount() const +{ + return m_bodyCount; +} + +inline int32 b2World::GetJointCount() const +{ + return m_jointCount; +} + +inline int32 b2World::GetContactCount() const +{ + return m_contactManager.m_contactCount; +} + +inline void b2World::SetGravity(const b2Vec2& gravity) +{ + m_gravity = gravity; +} + +inline b2Vec2 b2World::GetGravity() const +{ + return m_gravity; +} + +inline bool b2World::IsLocked() const +{ + return (m_flags & e_locked) == e_locked; +} + +inline void b2World::SetAutoClearForces(bool flag) +{ + if (flag) + { + m_flags |= e_clearForces; + } + else + { + m_flags &= ~e_clearForces; + } +} + +/// Get the flag that controls automatic clearing of forces after each time step. +inline bool b2World::GetAutoClearForces() const +{ + return (m_flags & e_clearForces) == e_clearForces; +} + +inline const b2ContactManager& b2World::GetContactManager() const +{ + return m_contactManager; +} + +inline const b2Profile& b2World::GetProfile() const +{ + return m_profile; +} + +#endif diff --git a/external/box2d/Dynamics/b2WorldCallbacks.cpp b/external/box2d/Dynamics/b2WorldCallbacks.cpp new file mode 100644 index 0000000000..48ad0cc46a --- /dev/null +++ b/external/box2d/Dynamics/b2WorldCallbacks.cpp @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2006-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 +#include + +// Return true if contact calculations should be performed between these two shapes. +// If you implement your own collision filter you may want to build from this implementation. +bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) +{ + const b2Filter& filterA = fixtureA->GetFilterData(); + const b2Filter& filterB = fixtureB->GetFilterData(); + + if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) + { + return filterA.groupIndex > 0; + } + + bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; + return collide; +} diff --git a/external/box2d/Dynamics/b2WorldCallbacks.h b/external/box2d/Dynamics/b2WorldCallbacks.h new file mode 100644 index 0000000000..86c04e3e32 --- /dev/null +++ b/external/box2d/Dynamics/b2WorldCallbacks.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_WORLD_CALLBACKS_H +#define B2_WORLD_CALLBACKS_H + +#include + +struct b2Vec2; +struct b2Transform; +class b2Fixture; +class b2Body; +class b2Joint; +class b2Contact; +struct b2ContactResult; +struct b2Manifold; + +/// Joints and fixtures are destroyed when their associated +/// body is destroyed. Implement this listener so that you +/// may nullify references to these joints and shapes. +class b2DestructionListener +{ +public: + virtual ~b2DestructionListener() {} + + /// Called when any joint is about to be destroyed due + /// to the destruction of one of its attached bodies. + virtual void SayGoodbye(b2Joint* joint) = 0; + + /// Called when any fixture is about to be destroyed due + /// to the destruction of its parent body. + virtual void SayGoodbye(b2Fixture* fixture) = 0; +}; + +/// Implement this class to provide collision filtering. In other words, you can implement +/// this class if you want finer control over contact creation. +class b2ContactFilter +{ +public: + virtual ~b2ContactFilter() {} + + /// Return true if contact calculations should be performed between these two shapes. + /// @warning for performance reasons this is only called when the AABBs begin to overlap. + virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); +}; + +/// Contact impulses for reporting. Impulses are used instead of forces because +/// sub-step forces may approach infinity for rigid body collisions. These +/// match up one-to-one with the contact points in b2Manifold. +struct b2ContactImpulse +{ + float32 normalImpulses[b2_maxManifoldPoints]; + float32 tangentImpulses[b2_maxManifoldPoints]; + int32 count; +}; + +/// Implement this class to get contact information. You can use these results for +/// things like sounds and game logic. You can also get contact results by +/// traversing the contact lists after the time step. However, you might miss +/// some contacts because continuous physics leads to sub-stepping. +/// Additionally you may receive multiple callbacks for the same contact in a +/// single time step. +/// You should strive to make your callbacks efficient because there may be +/// many callbacks per time step. +/// @warning You cannot create/destroy Box2D entities inside these callbacks. +class b2ContactListener +{ +public: + virtual ~b2ContactListener() {} + + /// Called when two fixtures begin to touch. + virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// Called when two fixtures cease to touch. + virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// This is called after a contact is updated. This allows you to inspect a + /// contact before it goes to the solver. If you are careful, you can modify the + /// contact manifold (e.g. disable contact). + /// A copy of the old manifold is provided so that you can detect changes. + /// Note: this is called only for awake bodies. + /// Note: this is called even when the number of contact points is zero. + /// Note: this is not called for sensors. + /// Note: if you set the number of contact points to zero, you will not + /// get an EndContact callback. However, you may get a BeginContact callback + /// the next step. + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + B2_NOT_USED(contact); + B2_NOT_USED(oldManifold); + } + + /// This lets you inspect a contact after the solver is finished. This is useful + /// for inspecting impulses. + /// Note: the contact manifold does not include time of impact impulses, which can be + /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly + /// in a separate data structure. + /// Note: this is only called for contacts that are touching, solid, and awake. + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + B2_NOT_USED(contact); + B2_NOT_USED(impulse); + } +}; + +/// Callback class for AABB queries. +/// See b2World::Query +class b2QueryCallback +{ +public: + virtual ~b2QueryCallback() {} + + /// Called for each fixture found in the query AABB. + /// @return false to terminate the query. + virtual bool ReportFixture(b2Fixture* fixture) = 0; +}; + +/// Callback class for ray casts. +/// See b2World::RayCast +class b2RayCastCallback +{ +public: + virtual ~b2RayCastCallback() {} + + /// Called for each fixture found in the query. You control how the ray cast + /// proceeds by returning a float: + /// return -1: ignore this fixture and continue + /// return 0: terminate the ray cast + /// return fraction: clip the ray to this point + /// return 1: don't clip the ray and continue + /// @param fixture the fixture hit by the ray + /// @param point the point of initial intersection + /// @param normal the normal vector at the point of intersection + /// @return -1 to filter, 0 to terminate, fraction to clip the ray for + /// closest hit, 1 to continue + virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) = 0; +}; + +#endif diff --git a/external/box2d/Rope/b2Rope.cpp b/external/box2d/Rope/b2Rope.cpp new file mode 100644 index 0000000000..9bf671aec9 --- /dev/null +++ b/external/box2d/Rope/b2Rope.cpp @@ -0,0 +1,259 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 +#include + +b2Rope::b2Rope() +{ + m_count = 0; + m_ps = NULL; + m_p0s = NULL; + m_vs = NULL; + m_ims = NULL; + m_Ls = NULL; + m_as = NULL; + m_gravity.SetZero(); + m_k2 = 1.0f; + m_k3 = 0.1f; +} + +b2Rope::~b2Rope() +{ + b2Free(m_ps); + b2Free(m_p0s); + b2Free(m_vs); + b2Free(m_ims); + b2Free(m_Ls); + b2Free(m_as); +} + +void b2Rope::Initialize(const b2RopeDef* def) +{ + b2Assert(def->count >= 3); + m_count = def->count; + m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_ims = (float32*)b2Alloc(m_count * sizeof(float32)); + + for (int32 i = 0; i < m_count; ++i) + { + m_ps[i] = def->vertices[i]; + m_p0s[i] = def->vertices[i]; + m_vs[i].SetZero(); + + float32 m = def->masses[i]; + if (m > 0.0f) + { + m_ims[i] = 1.0f / m; + } + else + { + m_ims[i] = 0.0f; + } + } + + int32 count2 = m_count - 1; + int32 count3 = m_count - 2; + m_Ls = (float32*)b2Alloc(count2 * sizeof(float32)); + m_as = (float32*)b2Alloc(count3 * sizeof(float32)); + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i+1]; + m_Ls[i] = b2Distance(p1, p2); + } + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + m_as[i] = b2Atan2(a, b); + } + + m_gravity = def->gravity; + m_damping = def->damping; + m_k2 = def->k2; + m_k3 = def->k3; +} + +void b2Rope::Step(float32 h, int32 iterations) +{ + if (h == 0.0) + { + return; + } + + float32 d = expf(- h * m_damping); + + for (int32 i = 0; i < m_count; ++i) + { + m_p0s[i] = m_ps[i]; + if (m_ims[i] > 0.0f) + { + m_vs[i] += h * m_gravity; + } + m_vs[i] *= d; + m_ps[i] += h * m_vs[i]; + + } + + for (int32 i = 0; i < iterations; ++i) + { + SolveC2(); + SolveC3(); + SolveC2(); + } + + float32 inv_h = 1.0f / h; + for (int32 i = 0; i < m_count; ++i) + { + m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]); + } +} + +void b2Rope::SolveC2() +{ + int32 count2 = m_count - 1; + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + + b2Vec2 d = p2 - p1; + float32 L = d.Normalize(); + + float32 im1 = m_ims[i]; + float32 im2 = m_ims[i + 1]; + + if (im1 + im2 == 0.0f) + { + continue; + } + + float32 s1 = im1 / (im1 + im2); + float32 s2 = im2 / (im1 + im2); + + p1 -= m_k2 * s1 * (m_Ls[i] - L) * d; + p2 += m_k2 * s2 * (m_Ls[i] - L) * d; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + } +} + +void b2Rope::SetAngle(float32 angle) +{ + int32 count3 = m_count - 2; + for (int32 i = 0; i < count3; ++i) + { + m_as[i] = angle; + } +} + +void b2Rope::SolveC3() +{ + int32 count3 = m_count - 2; + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + float32 m1 = m_ims[i]; + float32 m2 = m_ims[i + 1]; + float32 m3 = m_ims[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 L1sqr = d1.LengthSquared(); + float32 L2sqr = d2.LengthSquared(); + + if (L1sqr * L2sqr == 0.0f) + { + continue; + } + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + float32 angle = b2Atan2(a, b); + + b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew(); + b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew(); + + b2Vec2 J1 = -Jd1; + b2Vec2 J2 = Jd1 - Jd2; + b2Vec2 J3 = Jd2; + + float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3); + if (mass == 0.0f) + { + continue; + } + + mass = 1.0f / mass; + + float32 C = angle - m_as[i]; + + while (C > b2_pi) + { + angle -= 2 * b2_pi; + C = angle - m_as[i]; + } + + while (C < -b2_pi) + { + angle += 2.0f * b2_pi; + C = angle - m_as[i]; + } + + float32 impulse = - m_k3 * mass * C; + + p1 += (m1 * impulse) * J1; + p2 += (m2 * impulse) * J2; + p3 += (m3 * impulse) * J3; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + m_ps[i + 2] = p3; + } +} + +void b2Rope::Draw(b2Draw* draw) const +{ + b2Color c(0.4f, 0.5f, 0.7f); + + for (int32 i = 0; i < m_count - 1; ++i) + { + draw->DrawSegment(m_ps[i], m_ps[i+1], c); + } +} diff --git a/external/box2d/Rope/b2Rope.h b/external/box2d/Rope/b2Rope.h new file mode 100644 index 0000000000..b981dfd6c5 --- /dev/null +++ b/external/box2d/Rope/b2Rope.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef B2_ROPE_H +#define B2_ROPE_H + +#include + +class b2Draw; + +/// +struct b2RopeDef +{ + b2RopeDef() + { + vertices = NULL; + count = 0; + masses = NULL; + gravity.SetZero(); + damping = 0.1f; + k2 = 0.9f; + k3 = 0.1f; + } + + /// + b2Vec2* vertices; + + /// + int32 count; + + /// + float32* masses; + + /// + b2Vec2 gravity; + + /// + float32 damping; + + /// Stretching stiffness + float32 k2; + + /// Bending stiffness. Values above 0.5 can make the simulation blow up. + float32 k3; +}; + +/// +class b2Rope +{ +public: + b2Rope(); + ~b2Rope(); + + /// + void Initialize(const b2RopeDef* def); + + /// + void Step(float32 timeStep, int32 iterations); + + /// + int32 GetVertexCount() const + { + return m_count; + } + + /// + const b2Vec2* GetVertices() const + { + return m_ps; + } + + /// + void Draw(b2Draw* draw) const; + + /// + void SetAngle(float32 angle); + +private: + + void SolveC2(); + void SolveC3(); + + int32 m_count; + b2Vec2* m_ps; + b2Vec2* m_p0s; + b2Vec2* m_vs; + + float32* m_ims; + + float32* m_Ls; + float32* m_as; + + b2Vec2 m_gravity; + float32 m_damping; + + float32 m_k2; + float32 m_k3; +}; + +#endif diff --git a/external/box2d/proj.linux/.cproject b/external/box2d/proj.linux/.cproject new file mode 100644 index 0000000000..5aa092cac3 --- /dev/null +++ b/external/box2d/proj.linux/.cproject @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/box2d/proj.linux/.project b/external/box2d/proj.linux/.project new file mode 100644 index 0000000000..164d50f52a --- /dev/null +++ b/external/box2d/proj.linux/.project @@ -0,0 +1,110 @@ + + + libBox2D + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${workspace_loc:/libBox2D/Debug} + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + Box2D.h + 1 + PARENT-1-PROJECT_LOC/Box2D.h + + + Collision + 2 + PARENT-1-PROJECT_LOC/Collision + + + Common + 2 + PARENT-1-PROJECT_LOC/Common + + + Dynamics + 2 + PARENT-1-PROJECT_LOC/Dynamics + + + Rope + 2 + PARENT-1-PROJECT_LOC/Rope + + + diff --git a/external/box2d/proj.linux/Makefile b/external/box2d/proj.linux/Makefile new file mode 100644 index 0000000000..e430bc9883 --- /dev/null +++ b/external/box2d/proj.linux/Makefile @@ -0,0 +1,72 @@ +TARGET = libbox2d.a + +SOURCES = ../Collision/Shapes/b2ChainShape.cpp \ +../Collision/Shapes/b2CircleShape.cpp \ +../Collision/Shapes/b2EdgeShape.cpp \ +../Collision/Shapes/b2PolygonShape.cpp \ +../Collision/b2BroadPhase.cpp \ +../Collision/b2CollideCircle.cpp \ +../Collision/b2CollideEdge.cpp \ +../Collision/b2CollidePolygon.cpp \ +../Collision/b2Collision.cpp \ +../Collision/b2Distance.cpp \ +../Collision/b2DynamicTree.cpp \ +../Collision/b2TimeOfImpact.cpp \ +../Common/b2BlockAllocator.cpp \ +../Common/b2Draw.cpp \ +../Common/b2Math.cpp \ +../Common/b2Settings.cpp \ +../Common/b2StackAllocator.cpp \ +../Common/b2Timer.cpp \ +../Dynamics/Contacts/b2ChainAndCircleContact.cpp \ +../Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ +../Dynamics/Contacts/b2CircleContact.cpp \ +../Dynamics/Contacts/b2Contact.cpp \ +../Dynamics/Contacts/b2ContactSolver.cpp \ +../Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ +../Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ +../Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ +../Dynamics/Contacts/b2PolygonContact.cpp \ +../Dynamics/Joints/b2DistanceJoint.cpp \ +../Dynamics/Joints/b2FrictionJoint.cpp \ +../Dynamics/Joints/b2GearJoint.cpp \ +../Dynamics/Joints/b2Joint.cpp \ +../Dynamics/Joints/b2MouseJoint.cpp \ +../Dynamics/Joints/b2PrismaticJoint.cpp \ +../Dynamics/Joints/b2PulleyJoint.cpp \ +../Dynamics/Joints/b2RevoluteJoint.cpp \ +../Dynamics/Joints/b2RopeJoint.cpp \ +../Dynamics/Joints/b2WeldJoint.cpp \ +../Dynamics/Joints/b2WheelJoint.cpp \ +../Dynamics/b2Body.cpp \ +../Dynamics/b2ContactManager.cpp \ +../Dynamics/b2Fixture.cpp \ +../Dynamics/b2Island.cpp \ +../Dynamics/b2World.cpp \ +../Dynamics/b2WorldCallbacks.cpp \ +../Rope/b2Rope.cpp + +include ../../../cocos2dx/proj.linux/cocos2dx.mk + +INCLUDES = -I../.. + +# Cocos2d is not responsible for warnings in external projects +CXXFLAGS += -w + +ifeq ($(DEBUG), 1) +DEFINES = -D_DEBUG +else +DEFINES = +endif + +TARGET := $(LIB_DIR)/$(TARGET) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) + @mkdir -p $(@D) + $(LOG_AR)$(AR) $(ARFLAGS) $(TARGET) $(OBJECTS) + +$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) + @mkdir -p $(@D) + $(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/external/box2d/proj.linux/box2d.prf b/external/box2d/proj.linux/box2d.prf new file mode 100644 index 0000000000..434ad88406 --- /dev/null +++ b/external/box2d/proj.linux/box2d.prf @@ -0,0 +1,19 @@ +################################################################################ +# Do not include this file in your project: see cocos2dx.pri. +################################################################################ + +linux { + # We will compile box2d on demand using Makefile. + build_box2d.name = Build box2d static library + build_box2d.input = $$PWD/Makefile + build_box2d.output = $$CC_LIBRARY_DIR/libbox2d.a + build_box2d.target = $$CC_LIBRARY_DIR/libbox2d.a + build_box2d.CONFIG = no_link target_predeps + build_box2d.commands = cd $$PWD && make $$CC_MAKE_FLAGS + + QMAKE_EXTRA_COMPILERS += build_box2d + QMAKE_EXTRA_TARGETS += build_box2d + + PRE_TARGETDEPS += $$CC_LIBRARY_DIR/libbox2d.a + LIBS += -Wl,-Bstatic -lbox2d -Wl,-Bdynamic +} diff --git a/external/box2d/proj.win32/Box2D.vcxproj b/external/box2d/proj.win32/Box2D.vcxproj new file mode 100644 index 0000000000..cd4bd2086c --- /dev/null +++ b/external/box2d/proj.win32/Box2D.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + libBox2D + {929480E7-23C0-4DF6-8456-096D71547116} + Box2D.win32 + Win32Proj + + + + StaticLibrary + Unicode + v100 + v110 + v110_xp + + + StaticLibrary + Unicode + v100 + v110 + v110_xp + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration).win32\ + $(Configuration).win32\ + $(SolutionDir)$(Configuration).win32\ + $(Configuration).win32\ + AllRules.ruleset + + + AllRules.ruleset + + + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) + + + + Disabled + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + true + + + $(OutDir)$(ProjectName).lib + + + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + true + + + $(OutDir)$(ProjectName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/box2d/proj.win32/Box2D.vcxproj.filters b/external/box2d/proj.win32/Box2D.vcxproj.filters new file mode 100644 index 0000000000..e810cbb0cf --- /dev/null +++ b/external/box2d/proj.win32/Box2D.vcxproj.filters @@ -0,0 +1,301 @@ + + + + + {bdf099c5-cc32-468b-b53f-ec010d7f823f} + + + {92792f88-4e5c-46ee-8d87-002f3b2297ae} + + + {f41a6fa6-5ac1-4514-9ac0-6f3a38f35b4d} + + + {0b56913a-34b7-410a-b386-869d6f7a20be} + + + {f0e7b230-79cc-49b8-9ed7-9dbfa062f2a4} + + + {932f2008-afbe-42f5-993d-a1df0ec67756} + + + {f8937e09-93a4-49fa-8f3e-dfc36da764df} + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + + \ No newline at end of file diff --git a/external/box2d/proj.win32/Box2D.vcxproj.user b/external/box2d/proj.win32/Box2D.vcxproj.user new file mode 100644 index 0000000000..ace9a86acb --- /dev/null +++ b/external/box2d/proj.win32/Box2D.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 31b92aacc4e2ec24734417e465fc191828e5a5a0 Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 14:10:18 +0800 Subject: [PATCH 110/116] issue #2905: remove rpm, don't support qt5 temporaly --- rpm/cocos2d-x.spec | 81 ---------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 rpm/cocos2d-x.spec diff --git a/rpm/cocos2d-x.spec b/rpm/cocos2d-x.spec deleted file mode 100644 index c997278f21..0000000000 --- a/rpm/cocos2d-x.spec +++ /dev/null @@ -1,81 +0,0 @@ -Name: cocos2d-x -Version: 1.0.0 -Release: 2 -Summary: Cocos2D-X Cross-Platform 2D Games Framework - -Group: System/GUI/Other -License: MIT -URL: http://cocos2d-x.org -Source: %{name}-%{version}.tar.bz2 -BuildRequires: pkgconfig(egl) -BuildRequires: pkgconfig(glesv2) -BuildRequires: pkgconfig(Qt5Core) -BuildRequires: pkgconfig(Qt5Gui) -BuildRequires: pkgconfig(Qt5Multimedia) -BuildRequires: pkgconfig(Qt5Sensors) -BuildRequires: pkgconfig(zlib) -BuildRequires: pkgconfig(fontconfig) -BuildRequires: pkgconfig(freetype2) -BuildRequires: pkgconfig(libpng) -BuildRequires: pkgconfig(libtiff-4) -BuildRequires: libjpeg-turbo-devel -BuildRequires: pkgconfig(libcurl) - -%description -cocos2d-x is a multi-platform 2D game framework in C++, -branched on cocos2d-iphone and licensed under MIT. - -%package tests -Summary: Cocos2D-X Test Applications -Group: Development/Libraries -Requires: %{name} = %{version} - -%description tests -cocos2d-x is a multi-platform 2D game framework in C++, -branched on cocos2d-iphone and licensed under MIT. - -This package contains test applications for Cocos2D-X. - -%package devel -Summary: Cocos2D-X Development Libraries -Group: Development/Libraries -Requires: %{name} = %{version} - -%description devel -cocos2d-x is a multi-platform 2D game framework in C++, -branched on cocos2d-iphone and licensed under MIT. - -This package contains development libraries for Cocos2D-X. - -%prep -%setup -q - -%build -%qmake5 -make - -%install -make INSTALL_ROOT=%{buildroot} install - -%post -/sbin/ldconfig - -%postun -/sbin/ldconfig - -%files -%defattr(-,root,root,-) -%doc README.mdown licenses -%{_libdir}/lib*.so.* - -%files tests -%defattr(-,root,root,-) -%doc README.mdown -/opt/cocos2dx_TestCpp/* -/usr/share/applications/*.desktop - -%files devel -%defattr(-,root,root,-) -%doc README.mdown AUTHORS CHANGELOG -%{_libdir}/lib*.so -#%{_includedir}/*/*.h From dfe85aa125535fafd3a40221c863dd692086fa0f Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 14:14:57 +0800 Subject: [PATCH 111/116] issue #2905:remove box2d --- external/box2d/Android.mk | 60 - external/box2d/Box2D.h | 67 - .../box2d/Collision/Shapes/b2ChainShape.cpp | 171 --- .../box2d/Collision/Shapes/b2ChainShape.h | 102 -- .../box2d/Collision/Shapes/b2CircleShape.cpp | 100 -- .../box2d/Collision/Shapes/b2CircleShape.h | 91 -- .../box2d/Collision/Shapes/b2EdgeShape.cpp | 139 -- external/box2d/Collision/Shapes/b2EdgeShape.h | 74 - .../box2d/Collision/Shapes/b2PolygonShape.cpp | 361 ----- .../box2d/Collision/Shapes/b2PolygonShape.h | 95 -- external/box2d/Collision/Shapes/b2Shape.h | 101 -- external/box2d/Collision/b2BroadPhase.cpp | 122 -- external/box2d/Collision/b2BroadPhase.h | 248 ---- external/box2d/Collision/b2CollideCircle.cpp | 154 -- external/box2d/Collision/b2CollideEdge.cpp | 698 --------- external/box2d/Collision/b2CollidePolygon.cpp | 317 ---- external/box2d/Collision/b2Collision.cpp | 249 ---- external/box2d/Collision/b2Collision.h | 276 ---- external/box2d/Collision/b2Distance.cpp | 603 -------- external/box2d/Collision/b2Distance.h | 141 -- external/box2d/Collision/b2DynamicTree.cpp | 775 ---------- external/box2d/Collision/b2DynamicTree.h | 284 ---- external/box2d/Collision/b2TimeOfImpact.cpp | 488 ------ external/box2d/Collision/b2TimeOfImpact.h | 58 - external/box2d/Common/b2BlockAllocator.cpp | 218 --- external/box2d/Common/b2BlockAllocator.h | 62 - external/box2d/Common/b2Draw.cpp | 44 - external/box2d/Common/b2Draw.h | 81 - external/box2d/Common/b2GrowableStack.h | 85 -- external/box2d/Common/b2Math.cpp | 94 -- external/box2d/Common/b2Math.h | 738 --------- external/box2d/Common/b2Settings.cpp | 61 - external/box2d/Common/b2Settings.h | 150 -- external/box2d/Common/b2StackAllocator.cpp | 83 -- external/box2d/Common/b2StackAllocator.h | 60 - external/box2d/Common/b2Timer.cpp | 100 -- external/box2d/Common/b2Timer.h | 45 - .../Contacts/b2ChainAndCircleContact.cpp | 54 - .../Contacts/b2ChainAndCircleContact.h | 39 - .../Contacts/b2ChainAndPolygonContact.cpp | 54 - .../Contacts/b2ChainAndPolygonContact.h | 39 - .../Dynamics/Contacts/b2CircleContact.cpp | 53 - .../box2d/Dynamics/Contacts/b2CircleContact.h | 39 - .../box2d/Dynamics/Contacts/b2Contact.cpp | 240 --- external/box2d/Dynamics/Contacts/b2Contact.h | 331 ----- .../Dynamics/Contacts/b2ContactSolver.cpp | 832 ----------- .../box2d/Dynamics/Contacts/b2ContactSolver.h | 94 -- .../Contacts/b2EdgeAndCircleContact.cpp | 50 - .../Contacts/b2EdgeAndCircleContact.h | 39 - .../Contacts/b2EdgeAndPolygonContact.cpp | 50 - .../Contacts/b2EdgeAndPolygonContact.h | 39 - .../Contacts/b2PolygonAndCircleContact.cpp | 50 - .../Contacts/b2PolygonAndCircleContact.h | 38 - .../Dynamics/Contacts/b2PolygonContact.cpp | 53 - .../Dynamics/Contacts/b2PolygonContact.h | 39 - .../box2d/Dynamics/Joints/b2DistanceJoint.cpp | 260 ---- .../box2d/Dynamics/Joints/b2DistanceJoint.h | 169 --- .../box2d/Dynamics/Joints/b2FrictionJoint.cpp | 251 ---- .../box2d/Dynamics/Joints/b2FrictionJoint.h | 119 -- .../box2d/Dynamics/Joints/b2GearJoint.cpp | 423 ------ external/box2d/Dynamics/Joints/b2GearJoint.h | 125 -- external/box2d/Dynamics/Joints/b2Joint.cpp | 199 --- external/box2d/Dynamics/Joints/b2Joint.h | 222 --- .../box2d/Dynamics/Joints/b2MouseJoint.cpp | 217 --- external/box2d/Dynamics/Joints/b2MouseJoint.h | 126 -- .../Dynamics/Joints/b2PrismaticJoint.cpp | 637 -------- .../box2d/Dynamics/Joints/b2PrismaticJoint.h | 196 --- .../box2d/Dynamics/Joints/b2PulleyJoint.cpp | 332 ----- .../box2d/Dynamics/Joints/b2PulleyJoint.h | 143 -- .../box2d/Dynamics/Joints/b2RevoluteJoint.cpp | 504 ------- .../box2d/Dynamics/Joints/b2RevoluteJoint.h | 204 --- .../box2d/Dynamics/Joints/b2RopeJoint.cpp | 241 --- external/box2d/Dynamics/Joints/b2RopeJoint.h | 114 -- .../box2d/Dynamics/Joints/b2WeldJoint.cpp | 330 ----- external/box2d/Dynamics/Joints/b2WeldJoint.h | 126 -- .../box2d/Dynamics/Joints/b2WheelJoint.cpp | 419 ------ external/box2d/Dynamics/Joints/b2WheelJoint.h | 213 --- external/box2d/Dynamics/b2Body.cpp | 514 ------- external/box2d/Dynamics/b2Body.h | 846 ----------- external/box2d/Dynamics/b2ContactManager.cpp | 293 ---- external/box2d/Dynamics/b2ContactManager.h | 52 - external/box2d/Dynamics/b2Fixture.cpp | 303 ---- external/box2d/Dynamics/b2Fixture.h | 345 ----- external/box2d/Dynamics/b2Island.cpp | 539 ------- external/box2d/Dynamics/b2Island.h | 93 -- external/box2d/Dynamics/b2TimeStep.h | 70 - external/box2d/Dynamics/b2World.cpp | 1316 ----------------- external/box2d/Dynamics/b2World.h | 349 ----- external/box2d/Dynamics/b2WorldCallbacks.cpp | 36 - external/box2d/Dynamics/b2WorldCallbacks.h | 155 -- external/box2d/Rope/b2Rope.cpp | 259 ---- external/box2d/Rope/b2Rope.h | 115 -- external/box2d/proj.linux/.cproject | 267 ---- external/box2d/proj.linux/.project | 110 -- external/box2d/proj.linux/Makefile | 72 - external/box2d/proj.linux/box2d.prf | 19 - external/box2d/proj.win32/Box2D.vcxproj | 194 --- .../box2d/proj.win32/Box2D.vcxproj.filters | 301 ---- external/box2d/proj.win32/Box2D.vcxproj.user | 3 - 99 files changed, 21549 deletions(-) delete mode 100644 external/box2d/Android.mk delete mode 100644 external/box2d/Box2D.h delete mode 100644 external/box2d/Collision/Shapes/b2ChainShape.cpp delete mode 100644 external/box2d/Collision/Shapes/b2ChainShape.h delete mode 100644 external/box2d/Collision/Shapes/b2CircleShape.cpp delete mode 100644 external/box2d/Collision/Shapes/b2CircleShape.h delete mode 100644 external/box2d/Collision/Shapes/b2EdgeShape.cpp delete mode 100644 external/box2d/Collision/Shapes/b2EdgeShape.h delete mode 100644 external/box2d/Collision/Shapes/b2PolygonShape.cpp delete mode 100644 external/box2d/Collision/Shapes/b2PolygonShape.h delete mode 100644 external/box2d/Collision/Shapes/b2Shape.h delete mode 100644 external/box2d/Collision/b2BroadPhase.cpp delete mode 100644 external/box2d/Collision/b2BroadPhase.h delete mode 100644 external/box2d/Collision/b2CollideCircle.cpp delete mode 100644 external/box2d/Collision/b2CollideEdge.cpp delete mode 100644 external/box2d/Collision/b2CollidePolygon.cpp delete mode 100644 external/box2d/Collision/b2Collision.cpp delete mode 100644 external/box2d/Collision/b2Collision.h delete mode 100644 external/box2d/Collision/b2Distance.cpp delete mode 100644 external/box2d/Collision/b2Distance.h delete mode 100644 external/box2d/Collision/b2DynamicTree.cpp delete mode 100644 external/box2d/Collision/b2DynamicTree.h delete mode 100644 external/box2d/Collision/b2TimeOfImpact.cpp delete mode 100644 external/box2d/Collision/b2TimeOfImpact.h delete mode 100644 external/box2d/Common/b2BlockAllocator.cpp delete mode 100644 external/box2d/Common/b2BlockAllocator.h delete mode 100644 external/box2d/Common/b2Draw.cpp delete mode 100644 external/box2d/Common/b2Draw.h delete mode 100644 external/box2d/Common/b2GrowableStack.h delete mode 100644 external/box2d/Common/b2Math.cpp delete mode 100644 external/box2d/Common/b2Math.h delete mode 100644 external/box2d/Common/b2Settings.cpp delete mode 100644 external/box2d/Common/b2Settings.h delete mode 100644 external/box2d/Common/b2StackAllocator.cpp delete mode 100644 external/box2d/Common/b2StackAllocator.h delete mode 100644 external/box2d/Common/b2Timer.cpp delete mode 100644 external/box2d/Common/b2Timer.h delete mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2CircleContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2CircleContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2Contact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2Contact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2ContactSolver.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2ContactSolver.h delete mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h delete mode 100644 external/box2d/Dynamics/Contacts/b2PolygonContact.cpp delete mode 100644 external/box2d/Dynamics/Contacts/b2PolygonContact.h delete mode 100644 external/box2d/Dynamics/Joints/b2DistanceJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2DistanceJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2FrictionJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2FrictionJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2GearJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2GearJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2Joint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2Joint.h delete mode 100644 external/box2d/Dynamics/Joints/b2MouseJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2MouseJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2PrismaticJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2PulleyJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2PulleyJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2RevoluteJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2RopeJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2RopeJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2WeldJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2WeldJoint.h delete mode 100644 external/box2d/Dynamics/Joints/b2WheelJoint.cpp delete mode 100644 external/box2d/Dynamics/Joints/b2WheelJoint.h delete mode 100644 external/box2d/Dynamics/b2Body.cpp delete mode 100644 external/box2d/Dynamics/b2Body.h delete mode 100644 external/box2d/Dynamics/b2ContactManager.cpp delete mode 100644 external/box2d/Dynamics/b2ContactManager.h delete mode 100644 external/box2d/Dynamics/b2Fixture.cpp delete mode 100644 external/box2d/Dynamics/b2Fixture.h delete mode 100644 external/box2d/Dynamics/b2Island.cpp delete mode 100644 external/box2d/Dynamics/b2Island.h delete mode 100644 external/box2d/Dynamics/b2TimeStep.h delete mode 100644 external/box2d/Dynamics/b2World.cpp delete mode 100644 external/box2d/Dynamics/b2World.h delete mode 100644 external/box2d/Dynamics/b2WorldCallbacks.cpp delete mode 100644 external/box2d/Dynamics/b2WorldCallbacks.h delete mode 100644 external/box2d/Rope/b2Rope.cpp delete mode 100644 external/box2d/Rope/b2Rope.h delete mode 100644 external/box2d/proj.linux/.cproject delete mode 100644 external/box2d/proj.linux/.project delete mode 100644 external/box2d/proj.linux/Makefile delete mode 100644 external/box2d/proj.linux/box2d.prf delete mode 100644 external/box2d/proj.win32/Box2D.vcxproj delete mode 100644 external/box2d/proj.win32/Box2D.vcxproj.filters delete mode 100644 external/box2d/proj.win32/Box2D.vcxproj.user diff --git a/external/box2d/Android.mk b/external/box2d/Android.mk deleted file mode 100644 index c366750c01..0000000000 --- a/external/box2d/Android.mk +++ /dev/null @@ -1,60 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := box2d_static - -LOCAL_MODULE_FILENAME := libbox2d - -LOCAL_SRC_FILES := \ -Collision/b2BroadPhase.cpp \ -Collision/b2CollideCircle.cpp \ -Collision/b2CollideEdge.cpp \ -Collision/b2CollidePolygon.cpp \ -Collision/b2Collision.cpp \ -Collision/b2Distance.cpp \ -Collision/b2DynamicTree.cpp \ -Collision/b2TimeOfImpact.cpp \ -Collision/Shapes/b2ChainShape.cpp \ -Collision/Shapes/b2CircleShape.cpp \ -Collision/Shapes/b2EdgeShape.cpp \ -Collision/Shapes/b2PolygonShape.cpp \ -Common/b2BlockAllocator.cpp \ -Common/b2Draw.cpp \ -Common/b2Math.cpp \ -Common/b2Settings.cpp \ -Common/b2StackAllocator.cpp \ -Common/b2Timer.cpp \ -Dynamics/b2Body.cpp \ -Dynamics/b2ContactManager.cpp \ -Dynamics/b2Fixture.cpp \ -Dynamics/b2Island.cpp \ -Dynamics/b2World.cpp \ -Dynamics/b2WorldCallbacks.cpp \ -Dynamics/Contacts/b2ChainAndCircleContact.cpp \ -Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ -Dynamics/Contacts/b2CircleContact.cpp \ -Dynamics/Contacts/b2Contact.cpp \ -Dynamics/Contacts/b2ContactSolver.cpp \ -Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ -Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ -Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ -Dynamics/Contacts/b2PolygonContact.cpp \ -Dynamics/Joints/b2DistanceJoint.cpp \ -Dynamics/Joints/b2FrictionJoint.cpp \ -Dynamics/Joints/b2GearJoint.cpp \ -Dynamics/Joints/b2Joint.cpp \ -Dynamics/Joints/b2MouseJoint.cpp \ -Dynamics/Joints/b2PrismaticJoint.cpp \ -Dynamics/Joints/b2PulleyJoint.cpp \ -Dynamics/Joints/b2RevoluteJoint.cpp \ -Dynamics/Joints/b2RopeJoint.cpp \ -Dynamics/Joints/b2WeldJoint.cpp \ -Dynamics/Joints/b2WheelJoint.cpp \ -Rope/b2Rope.cpp - -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. - -include $(BUILD_STATIC_LIBRARY) diff --git a/external/box2d/Box2D.h b/external/box2d/Box2D.h deleted file mode 100644 index f674d82269..0000000000 --- a/external/box2d/Box2D.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef BOX2D_H -#define BOX2D_H - -/** -\mainpage Box2D API Documentation - -\section intro_sec Getting Started - -For documentation please see http://box2d.org/documentation.html - -For discussion please visit http://box2d.org/forum -*/ - -// These include files constitute the main Box2D API - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/external/box2d/Collision/Shapes/b2ChainShape.cpp b/external/box2d/Collision/Shapes/b2ChainShape.cpp deleted file mode 100644 index 79b4304b5b..0000000000 --- a/external/box2d/Collision/Shapes/b2ChainShape.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -using namespace std; - -b2ChainShape::~b2ChainShape() -{ - b2Free(m_vertices); - m_vertices = NULL; - m_count = 0; -} - -void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) -{ - b2Assert(m_vertices == NULL && m_count == 0); - b2Assert(count >= 3); - m_count = count + 1; - m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); - m_vertices[count] = m_vertices[0]; - m_prevVertex = m_vertices[m_count - 2]; - m_nextVertex = m_vertices[1]; - m_hasPrevVertex = true; - m_hasNextVertex = true; -} - -void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) -{ - b2Assert(m_vertices == NULL && m_count == 0); - b2Assert(count >= 2); - m_count = count; - m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); - memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); - m_hasPrevVertex = false; - m_hasNextVertex = false; -} - -void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) -{ - m_prevVertex = prevVertex; - m_hasPrevVertex = true; -} - -void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) -{ - m_nextVertex = nextVertex; - m_hasNextVertex = true; -} - -b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2ChainShape)); - b2ChainShape* clone = new (mem) b2ChainShape; - clone->CreateChain(m_vertices, m_count); - clone->m_prevVertex = m_prevVertex; - clone->m_nextVertex = m_nextVertex; - clone->m_hasPrevVertex = m_hasPrevVertex; - clone->m_hasNextVertex = m_hasNextVertex; - return clone; -} - -int32 b2ChainShape::GetChildCount() const -{ - // edge count = vertex count - 1 - return m_count - 1; -} - -void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const -{ - b2Assert(0 <= index && index < m_count - 1); - edge->m_type = b2Shape::e_edge; - edge->m_radius = m_radius; - - edge->m_vertex1 = m_vertices[index + 0]; - edge->m_vertex2 = m_vertices[index + 1]; - - if (index > 0) - { - edge->m_vertex0 = m_vertices[index - 1]; - edge->m_hasVertex0 = true; - } - else - { - edge->m_vertex0 = m_prevVertex; - edge->m_hasVertex0 = m_hasPrevVertex; - } - - if (index < m_count - 2) - { - edge->m_vertex3 = m_vertices[index + 2]; - edge->m_hasVertex3 = true; - } - else - { - edge->m_vertex3 = m_nextVertex; - edge->m_hasVertex3 = m_hasNextVertex; - } -} - -bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - B2_NOT_USED(xf); - B2_NOT_USED(p); - return false; -} - -bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - b2Assert(childIndex < m_count); - - b2EdgeShape edgeShape; - - int32 i1 = childIndex; - int32 i2 = childIndex + 1; - if (i2 == m_count) - { - i2 = 0; - } - - edgeShape.m_vertex1 = m_vertices[i1]; - edgeShape.m_vertex2 = m_vertices[i2]; - - return edgeShape.RayCast(output, input, xf, 0); -} - -void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - b2Assert(childIndex < m_count); - - int32 i1 = childIndex; - int32 i2 = childIndex + 1; - if (i2 == m_count) - { - i2 = 0; - } - - b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); - b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); - - aabb->lowerBound = b2Min(v1, v2); - aabb->upperBound = b2Max(v1, v2); -} - -void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const -{ - B2_NOT_USED(density); - - massData->mass = 0.0f; - massData->center.SetZero(); - massData->I = 0.0f; -} diff --git a/external/box2d/Collision/Shapes/b2ChainShape.h b/external/box2d/Collision/Shapes/b2ChainShape.h deleted file mode 100644 index 9c9a9eaa7d..0000000000 --- a/external/box2d/Collision/Shapes/b2ChainShape.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -* Copyright (c) 2006-2010 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. -*/ - -#ifndef B2_CHAIN_SHAPE_H -#define B2_CHAIN_SHAPE_H - -#include - -class b2EdgeShape; - -/// A chain shape is a free form sequence of line segments. -/// The chain has two-sided collision, so you can use inside and outside collision. -/// Therefore, you may use any winding order. -/// Since there may be many vertices, they are allocated using b2Alloc. -/// Connectivity information is used to create smooth collisions. -/// WARNING: The chain will not collide properly if there are self-intersections. -class b2ChainShape : public b2Shape -{ -public: - b2ChainShape(); - - /// The destructor frees the vertices using b2Free. - ~b2ChainShape(); - - /// Create a loop. This automatically adjusts connectivity. - /// @param vertices an array of vertices, these are copied - /// @param count the vertex count - void CreateLoop(const b2Vec2* vertices, int32 count); - - /// Create a chain with isolated end vertices. - /// @param vertices an array of vertices, these are copied - /// @param count the vertex count - void CreateChain(const b2Vec2* vertices, int32 count); - - /// Establish connectivity to a vertex that precedes the first vertex. - /// Don't call this for loops. - void SetPrevVertex(const b2Vec2& prevVertex); - - /// Establish connectivity to a vertex that follows the last vertex. - /// Don't call this for loops. - void SetNextVertex(const b2Vec2& nextVertex); - - /// Implement b2Shape. Vertices are cloned using b2Alloc. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Get a child edge. - void GetChildEdge(b2EdgeShape* edge, int32 index) const; - - /// This always return false. - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// Chains have zero mass. - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// The vertices. Owned by this class. - b2Vec2* m_vertices; - - /// The vertex count. - int32 m_count; - - b2Vec2 m_prevVertex, m_nextVertex; - bool m_hasPrevVertex, m_hasNextVertex; -}; - -inline b2ChainShape::b2ChainShape() -{ - m_type = e_chain; - m_radius = b2_polygonRadius; - m_vertices = NULL; - m_count = 0; - m_hasPrevVertex = false; - m_hasNextVertex = false; -} - -#endif diff --git a/external/box2d/Collision/Shapes/b2CircleShape.cpp b/external/box2d/Collision/Shapes/b2CircleShape.cpp deleted file mode 100644 index 587ca960b2..0000000000 --- a/external/box2d/Collision/Shapes/b2CircleShape.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -using namespace std; - -b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2CircleShape)); - b2CircleShape* clone = new (mem) b2CircleShape; - *clone = *this; - return clone; -} - -int32 b2CircleShape::GetChildCount() const -{ - return 1; -} - -bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const -{ - b2Vec2 center = transform.p + b2Mul(transform.q, m_p); - b2Vec2 d = p - center; - return b2Dot(d, d) <= m_radius * m_radius; -} - -// Collision Detection in Interactive 3D Environments by Gino van den Bergen -// From Section 3.1.2 -// x = s + a * r -// norm(x) = radius -bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 position = transform.p + b2Mul(transform.q, m_p); - b2Vec2 s = input.p1 - position; - float32 b = b2Dot(s, s) - m_radius * m_radius; - - // Solve quadratic equation. - b2Vec2 r = input.p2 - input.p1; - float32 c = b2Dot(s, r); - float32 rr = b2Dot(r, r); - float32 sigma = c * c - rr * b; - - // Check for negative discriminant and short segment. - if (sigma < 0.0f || rr < b2_epsilon) - { - return false; - } - - // Find the point of intersection of the line with the circle. - float32 a = -(c + b2Sqrt(sigma)); - - // Is the intersection point on the segment? - if (0.0f <= a && a <= input.maxFraction * rr) - { - a /= rr; - output->fraction = a; - output->normal = s + a * r; - output->normal.Normalize(); - return true; - } - - return false; -} - -void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 p = transform.p + b2Mul(transform.q, m_p); - aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); - aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); -} - -void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const -{ - massData->mass = density * b2_pi * m_radius * m_radius; - massData->center = m_p; - - // inertia about the local origin - massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); -} diff --git a/external/box2d/Collision/Shapes/b2CircleShape.h b/external/box2d/Collision/Shapes/b2CircleShape.h deleted file mode 100644 index c4e23a475b..0000000000 --- a/external/box2d/Collision/Shapes/b2CircleShape.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CIRCLE_SHAPE_H -#define B2_CIRCLE_SHAPE_H - -#include - -/// A circle shape. -class b2CircleShape : public b2Shape -{ -public: - b2CircleShape(); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Implement b2Shape. - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// Get the supporting vertex index in the given direction. - int32 GetSupport(const b2Vec2& d) const; - - /// Get the supporting vertex in the given direction. - const b2Vec2& GetSupportVertex(const b2Vec2& d) const; - - /// Get the vertex count. - int32 GetVertexCount() const { return 1; } - - /// Get a vertex by index. Used by b2Distance. - const b2Vec2& GetVertex(int32 index) const; - - /// Position - b2Vec2 m_p; -}; - -inline b2CircleShape::b2CircleShape() -{ - m_type = e_circle; - m_radius = 0.0f; - m_p.SetZero(); -} - -inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const -{ - B2_NOT_USED(d); - return 0; -} - -inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const -{ - B2_NOT_USED(d); - return m_p; -} - -inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const -{ - B2_NOT_USED(index); - b2Assert(index == 0); - return m_p; -} - -#endif diff --git a/external/box2d/Collision/Shapes/b2EdgeShape.cpp b/external/box2d/Collision/Shapes/b2EdgeShape.cpp deleted file mode 100644 index 7b09e55bf4..0000000000 --- a/external/box2d/Collision/Shapes/b2EdgeShape.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -using namespace std; - -void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) -{ - m_vertex1 = v1; - m_vertex2 = v2; - m_hasVertex0 = false; - m_hasVertex3 = false; -} - -b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2EdgeShape)); - b2EdgeShape* clone = new (mem) b2EdgeShape; - *clone = *this; - return clone; -} - -int32 b2EdgeShape::GetChildCount() const -{ - return 1; -} - -bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - B2_NOT_USED(xf); - B2_NOT_USED(p); - return false; -} - -// p = p1 + t * d -// v = v1 + s * e -// p1 + t * d = v1 + s * e -// s * e - t * d = p1 - v1 -bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - // Put the ray into the edge's frame of reference. - b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); - b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); - b2Vec2 d = p2 - p1; - - b2Vec2 v1 = m_vertex1; - b2Vec2 v2 = m_vertex2; - b2Vec2 e = v2 - v1; - b2Vec2 normal(e.y, -e.x); - normal.Normalize(); - - // q = p1 + t * d - // dot(normal, q - v1) = 0 - // dot(normal, p1 - v1) + t * dot(normal, d) = 0 - float32 numerator = b2Dot(normal, v1 - p1); - float32 denominator = b2Dot(normal, d); - - if (denominator == 0.0f) - { - return false; - } - - float32 t = numerator / denominator; - if (t < 0.0f || input.maxFraction < t) - { - return false; - } - - b2Vec2 q = p1 + t * d; - - // q = v1 + s * r - // s = dot(q - v1, r) / dot(r, r) - b2Vec2 r = v2 - v1; - float32 rr = b2Dot(r, r); - if (rr == 0.0f) - { - return false; - } - - float32 s = b2Dot(q - v1, r) / rr; - if (s < 0.0f || 1.0f < s) - { - return false; - } - - output->fraction = t; - if (numerator > 0.0f) - { - output->normal = -normal; - } - else - { - output->normal = normal; - } - return true; -} - -void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 v1 = b2Mul(xf, m_vertex1); - b2Vec2 v2 = b2Mul(xf, m_vertex2); - - b2Vec2 lower = b2Min(v1, v2); - b2Vec2 upper = b2Max(v1, v2); - - b2Vec2 r(m_radius, m_radius); - aabb->lowerBound = lower - r; - aabb->upperBound = upper + r; -} - -void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const -{ - B2_NOT_USED(density); - - massData->mass = 0.0f; - massData->center = 0.5f * (m_vertex1 + m_vertex2); - massData->I = 0.0f; -} diff --git a/external/box2d/Collision/Shapes/b2EdgeShape.h b/external/box2d/Collision/Shapes/b2EdgeShape.h deleted file mode 100644 index 6163bcbf1c..0000000000 --- a/external/box2d/Collision/Shapes/b2EdgeShape.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (c) 2006-2010 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. -*/ - -#ifndef B2_EDGE_SHAPE_H -#define B2_EDGE_SHAPE_H - -#include - -/// A line segment (edge) shape. These can be connected in chains or loops -/// to other edge shapes. The connectivity information is used to ensure -/// correct contact normals. -class b2EdgeShape : public b2Shape -{ -public: - b2EdgeShape(); - - /// Set this as an isolated edge. - void Set(const b2Vec2& v1, const b2Vec2& v2); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// These are the edge vertices - b2Vec2 m_vertex1, m_vertex2; - - /// Optional adjacent vertices. These are used for smooth collision. - b2Vec2 m_vertex0, m_vertex3; - bool m_hasVertex0, m_hasVertex3; -}; - -inline b2EdgeShape::b2EdgeShape() -{ - m_type = e_edge; - m_radius = b2_polygonRadius; - m_vertex0.x = 0.0f; - m_vertex0.y = 0.0f; - m_vertex3.x = 0.0f; - m_vertex3.y = 0.0f; - m_hasVertex0 = false; - m_hasVertex3 = false; -} - -#endif diff --git a/external/box2d/Collision/Shapes/b2PolygonShape.cpp b/external/box2d/Collision/Shapes/b2PolygonShape.cpp deleted file mode 100644 index c04c1dc49b..0000000000 --- a/external/box2d/Collision/Shapes/b2PolygonShape.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const -{ - void* mem = allocator->Allocate(sizeof(b2PolygonShape)); - b2PolygonShape* clone = new (mem) b2PolygonShape; - *clone = *this; - return clone; -} - -void b2PolygonShape::SetAsBox(float32 hx, float32 hy) -{ - m_vertexCount = 4; - m_vertices[0].Set(-hx, -hy); - m_vertices[1].Set( hx, -hy); - m_vertices[2].Set( hx, hy); - m_vertices[3].Set(-hx, hy); - m_normals[0].Set(0.0f, -1.0f); - m_normals[1].Set(1.0f, 0.0f); - m_normals[2].Set(0.0f, 1.0f); - m_normals[3].Set(-1.0f, 0.0f); - m_centroid.SetZero(); -} - -void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) -{ - m_vertexCount = 4; - m_vertices[0].Set(-hx, -hy); - m_vertices[1].Set( hx, -hy); - m_vertices[2].Set( hx, hy); - m_vertices[3].Set(-hx, hy); - m_normals[0].Set(0.0f, -1.0f); - m_normals[1].Set(1.0f, 0.0f); - m_normals[2].Set(0.0f, 1.0f); - m_normals[3].Set(-1.0f, 0.0f); - m_centroid = center; - - b2Transform xf; - xf.p = center; - xf.q.Set(angle); - - // Transform vertices and normals. - for (int32 i = 0; i < m_vertexCount; ++i) - { - m_vertices[i] = b2Mul(xf, m_vertices[i]); - m_normals[i] = b2Mul(xf.q, m_normals[i]); - } -} - -int32 b2PolygonShape::GetChildCount() const -{ - return 1; -} - -static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) -{ - b2Assert(count >= 3); - - b2Vec2 c; c.Set(0.0f, 0.0f); - float32 area = 0.0f; - - // pRef is the reference point for forming triangles. - // It's location doesn't change the result (except for rounding error). - b2Vec2 pRef(0.0f, 0.0f); -#if 0 - // This code would put the reference point inside the polygon. - for (int32 i = 0; i < count; ++i) - { - pRef += vs[i]; - } - pRef *= 1.0f / count; -#endif - - const float32 inv3 = 1.0f / 3.0f; - - for (int32 i = 0; i < count; ++i) - { - // Triangle vertices. - b2Vec2 p1 = pRef; - b2Vec2 p2 = vs[i]; - b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; - - b2Vec2 e1 = p2 - p1; - b2Vec2 e2 = p3 - p1; - - float32 D = b2Cross(e1, e2); - - float32 triangleArea = 0.5f * D; - area += triangleArea; - - // Area weighted centroid - c += triangleArea * inv3 * (p1 + p2 + p3); - } - - // Centroid - b2Assert(area > b2_epsilon); - c *= 1.0f / area; - return c; -} - -void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) -{ - b2Assert(3 <= count && count <= b2_maxPolygonVertices); - m_vertexCount = count; - - // Copy vertices. - for (int32 i = 0; i < m_vertexCount; ++i) - { - m_vertices[i] = vertices[i]; - } - - // Compute normals. Ensure the edges have non-zero length. - for (int32 i = 0; i < m_vertexCount; ++i) - { - int32 i1 = i; - int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; - b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; - b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); - m_normals[i] = b2Cross(edge, 1.0f); - m_normals[i].Normalize(); - } - -#ifdef _DEBUG - // Ensure the polygon is convex and the interior - // is to the left of each edge. - for (int32 i = 0; i < m_vertexCount; ++i) - { - int32 i1 = i; - int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; - b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; - - for (int32 j = 0; j < m_vertexCount; ++j) - { - // Don't check vertices on the current edge. - if (j == i1 || j == i2) - { - continue; - } - - b2Vec2 r = m_vertices[j] - m_vertices[i1]; - - // If this crashes, your polygon is non-convex, has colinear edges, - // or the winding order is wrong. - float32 s = b2Cross(edge, r); - b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order"); - } - } -#endif - - // Compute the polygon centroid. - m_centroid = ComputeCentroid(m_vertices, m_vertexCount); -} - -bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const -{ - b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); - - for (int32 i = 0; i < m_vertexCount; ++i) - { - float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); - if (dot > 0.0f) - { - return false; - } - } - - return true; -} - -bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - // Put the ray into the polygon's frame of reference. - b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); - b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); - b2Vec2 d = p2 - p1; - - float32 lower = 0.0f, upper = input.maxFraction; - - int32 index = -1; - - for (int32 i = 0; i < m_vertexCount; ++i) - { - // p = p1 + a * d - // dot(normal, p - v) = 0 - // dot(normal, p1 - v) + a * dot(normal, d) = 0 - float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); - float32 denominator = b2Dot(m_normals[i], d); - - if (denominator == 0.0f) - { - if (numerator < 0.0f) - { - return false; - } - } - else - { - // Note: we want this predicate without division: - // lower < numerator / denominator, where denominator < 0 - // Since denominator < 0, we have to flip the inequality: - // lower < numerator / denominator <==> denominator * lower > numerator. - if (denominator < 0.0f && numerator < lower * denominator) - { - // Increase lower. - // The segment enters this half-space. - lower = numerator / denominator; - index = i; - } - else if (denominator > 0.0f && numerator < upper * denominator) - { - // Decrease upper. - // The segment exits this half-space. - upper = numerator / denominator; - } - } - - // The use of epsilon here causes the assert on lower to trip - // in some cases. Apparently the use of epsilon was to make edge - // shapes work, but now those are handled separately. - //if (upper < lower - b2_epsilon) - if (upper < lower) - { - return false; - } - } - - b2Assert(0.0f <= lower && lower <= input.maxFraction); - - if (index >= 0) - { - output->fraction = lower; - output->normal = b2Mul(xf.q, m_normals[index]); - return true; - } - - return false; -} - -void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const -{ - B2_NOT_USED(childIndex); - - b2Vec2 lower = b2Mul(xf, m_vertices[0]); - b2Vec2 upper = lower; - - for (int32 i = 1; i < m_vertexCount; ++i) - { - b2Vec2 v = b2Mul(xf, m_vertices[i]); - lower = b2Min(lower, v); - upper = b2Max(upper, v); - } - - b2Vec2 r(m_radius, m_radius); - aabb->lowerBound = lower - r; - aabb->upperBound = upper + r; -} - -void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const -{ - // Polygon mass, centroid, and inertia. - // Let rho be the polygon density in mass per unit area. - // Then: - // mass = rho * int(dA) - // centroid.x = (1/mass) * rho * int(x * dA) - // centroid.y = (1/mass) * rho * int(y * dA) - // I = rho * int((x*x + y*y) * dA) - // - // We can compute these integrals by summing all the integrals - // for each triangle of the polygon. To evaluate the integral - // for a single triangle, we make a change of variables to - // the (u,v) coordinates of the triangle: - // x = x0 + e1x * u + e2x * v - // y = y0 + e1y * u + e2y * v - // where 0 <= u && 0 <= v && u + v <= 1. - // - // We integrate u from [0,1-v] and then v from [0,1]. - // We also need to use the Jacobian of the transformation: - // D = cross(e1, e2) - // - // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) - // - // The rest of the derivation is handled by computer algebra. - - b2Assert(m_vertexCount >= 3); - - b2Vec2 center; center.Set(0.0f, 0.0f); - float32 area = 0.0f; - float32 I = 0.0f; - - // s is the reference point for forming triangles. - // It's location doesn't change the result (except for rounding error). - b2Vec2 s(0.0f, 0.0f); - - // This code would put the reference point inside the polygon. - for (int32 i = 0; i < m_vertexCount; ++i) - { - s += m_vertices[i]; - } - s *= 1.0f / m_vertexCount; - - const float32 k_inv3 = 1.0f / 3.0f; - - for (int32 i = 0; i < m_vertexCount; ++i) - { - // Triangle vertices. - b2Vec2 e1 = m_vertices[i] - s; - b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s; - - float32 D = b2Cross(e1, e2); - - float32 triangleArea = 0.5f * D; - area += triangleArea; - - // Area weighted centroid - center += triangleArea * k_inv3 * (e1 + e2); - - float32 ex1 = e1.x, ey1 = e1.y; - float32 ex2 = e2.x, ey2 = e2.y; - - float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; - float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; - - I += (0.25f * k_inv3 * D) * (intx2 + inty2); - } - - // Total mass - massData->mass = density * area; - - // Center of mass - b2Assert(area > b2_epsilon); - center *= 1.0f / area; - massData->center = center + s; - - // Inertia tensor relative to the local origin (point s). - massData->I = density * I; - - // Shift to center of mass then to original body origin. - massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); -} diff --git a/external/box2d/Collision/Shapes/b2PolygonShape.h b/external/box2d/Collision/Shapes/b2PolygonShape.h deleted file mode 100644 index 70daccb2ff..0000000000 --- a/external/box2d/Collision/Shapes/b2PolygonShape.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_SHAPE_H -#define B2_POLYGON_SHAPE_H - -#include - -/// A convex polygon. It is assumed that the interior of the polygon is to -/// the left of each edge. -/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. -/// In most cases you should not need many vertices for a convex polygon. -class b2PolygonShape : public b2Shape -{ -public: - b2PolygonShape(); - - /// Implement b2Shape. - b2Shape* Clone(b2BlockAllocator* allocator) const; - - /// @see b2Shape::GetChildCount - int32 GetChildCount() const; - - /// Copy vertices. This assumes the vertices define a convex polygon. - /// It is assumed that the exterior is the the right of each edge. - /// The count must be in the range [3, b2_maxPolygonVertices]. - void Set(const b2Vec2* vertices, int32 vertexCount); - - /// Build vertices to represent an axis-aligned box. - /// @param hx the half-width. - /// @param hy the half-height. - void SetAsBox(float32 hx, float32 hy); - - /// Build vertices to represent an oriented box. - /// @param hx the half-width. - /// @param hy the half-height. - /// @param center the center of the box in local coordinates. - /// @param angle the rotation of the box in local coordinates. - void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); - - /// @see b2Shape::TestPoint - bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; - - /// Implement b2Shape. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeAABB - void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; - - /// @see b2Shape::ComputeMass - void ComputeMass(b2MassData* massData, float32 density) const; - - /// Get the vertex count. - int32 GetVertexCount() const { return m_vertexCount; } - - /// Get a vertex by index. - const b2Vec2& GetVertex(int32 index) const; - - b2Vec2 m_centroid; - b2Vec2 m_vertices[b2_maxPolygonVertices]; - b2Vec2 m_normals[b2_maxPolygonVertices]; - int32 m_vertexCount; -}; - -inline b2PolygonShape::b2PolygonShape() -{ - m_type = e_polygon; - m_radius = b2_polygonRadius; - m_vertexCount = 0; - m_centroid.SetZero(); -} - -inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const -{ - b2Assert(0 <= index && index < m_vertexCount); - return m_vertices[index]; -} - -#endif diff --git a/external/box2d/Collision/Shapes/b2Shape.h b/external/box2d/Collision/Shapes/b2Shape.h deleted file mode 100644 index 2e2aedd14a..0000000000 --- a/external/box2d/Collision/Shapes/b2Shape.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_SHAPE_H -#define B2_SHAPE_H - -#include -#include -#include - -/// This holds the mass data computed for a shape. -struct b2MassData -{ - /// The mass of the shape, usually in kilograms. - float32 mass; - - /// The position of the shape's centroid relative to the shape's origin. - b2Vec2 center; - - /// The rotational inertia of the shape about the local origin. - float32 I; -}; - -/// A shape is used for collision detection. You can create a shape however you like. -/// Shapes used for simulation in b2World are created automatically when a b2Fixture -/// is created. Shapes may encapsulate a one or more child shapes. -class b2Shape -{ -public: - - enum Type - { - e_circle = 0, - e_edge = 1, - e_polygon = 2, - e_chain = 3, - e_typeCount = 4 - }; - - virtual ~b2Shape() {} - - /// Clone the concrete shape using the provided allocator. - virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; - - /// Get the type of this shape. You can use this to down cast to the concrete shape. - /// @return the shape type. - Type GetType() const; - - /// Get the number of child primitives. - virtual int32 GetChildCount() const = 0; - - /// Test a point for containment in this shape. This only works for convex shapes. - /// @param xf the shape world transform. - /// @param p a point in world coordinates. - virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; - - /// Cast a ray against a child shape. - /// @param output the ray-cast results. - /// @param input the ray-cast input parameters. - /// @param transform the transform to be applied to the shape. - /// @param childIndex the child shape index - virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, - const b2Transform& transform, int32 childIndex) const = 0; - - /// Given a transform, compute the associated axis aligned bounding box for a child shape. - /// @param aabb returns the axis aligned box. - /// @param xf the world transform of the shape. - /// @param childIndex the child shape - virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; - - /// Compute the mass properties of this shape using its dimensions and density. - /// The inertia tensor is computed about the local origin. - /// @param massData returns the mass data for this shape. - /// @param density the density in kilograms per meter squared. - virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; - - Type m_type; - float32 m_radius; -}; - -inline b2Shape::Type b2Shape::GetType() const -{ - return m_type; -} - -#endif diff --git a/external/box2d/Collision/b2BroadPhase.cpp b/external/box2d/Collision/b2BroadPhase.cpp deleted file mode 100644 index 431f6de1ee..0000000000 --- a/external/box2d/Collision/b2BroadPhase.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -using namespace std; - -b2BroadPhase::b2BroadPhase() -{ - m_proxyCount = 0; - - m_pairCapacity = 16; - m_pairCount = 0; - m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); - - m_moveCapacity = 16; - m_moveCount = 0; - m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); -} - -b2BroadPhase::~b2BroadPhase() -{ - b2Free(m_moveBuffer); - b2Free(m_pairBuffer); -} - -int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) -{ - int32 proxyId = m_tree.CreateProxy(aabb, userData); - ++m_proxyCount; - BufferMove(proxyId); - return proxyId; -} - -void b2BroadPhase::DestroyProxy(int32 proxyId) -{ - UnBufferMove(proxyId); - --m_proxyCount; - m_tree.DestroyProxy(proxyId); -} - -void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) -{ - bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); - if (buffer) - { - BufferMove(proxyId); - } -} - -void b2BroadPhase::TouchProxy(int32 proxyId) -{ - BufferMove(proxyId); -} - -void b2BroadPhase::BufferMove(int32 proxyId) -{ - if (m_moveCount == m_moveCapacity) - { - int32* oldBuffer = m_moveBuffer; - m_moveCapacity *= 2; - m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); - memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); - b2Free(oldBuffer); - } - - m_moveBuffer[m_moveCount] = proxyId; - ++m_moveCount; -} - -void b2BroadPhase::UnBufferMove(int32 proxyId) -{ - for (int32 i = 0; i < m_moveCount; ++i) - { - if (m_moveBuffer[i] == proxyId) - { - m_moveBuffer[i] = e_nullProxy; - return; - } - } -} - -// This is called from b2DynamicTree::Query when we are gathering pairs. -bool b2BroadPhase::QueryCallback(int32 proxyId) -{ - // A proxy cannot form a pair with itself. - if (proxyId == m_queryProxyId) - { - return true; - } - - // Grow the pair buffer as needed. - if (m_pairCount == m_pairCapacity) - { - b2Pair* oldBuffer = m_pairBuffer; - m_pairCapacity *= 2; - m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); - memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); - b2Free(oldBuffer); - } - - m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); - m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); - ++m_pairCount; - - return true; -} diff --git a/external/box2d/Collision/b2BroadPhase.h b/external/box2d/Collision/b2BroadPhase.h deleted file mode 100644 index cf2414730a..0000000000 --- a/external/box2d/Collision/b2BroadPhase.h +++ /dev/null @@ -1,248 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_BROAD_PHASE_H -#define B2_BROAD_PHASE_H - -#include -#include -#include -#include - -struct b2Pair -{ - int32 proxyIdA; - int32 proxyIdB; - int32 next; -}; - -/// The broad-phase is used for computing pairs and performing volume queries and ray casts. -/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. -/// It is up to the client to consume the new pairs and to track subsequent overlap. -class b2BroadPhase -{ -public: - - enum - { - e_nullProxy = -1 - }; - - b2BroadPhase(); - ~b2BroadPhase(); - - /// Create a proxy with an initial AABB. Pairs are not reported until - /// UpdatePairs is called. - int32 CreateProxy(const b2AABB& aabb, void* userData); - - /// Destroy a proxy. It is up to the client to remove any pairs. - void DestroyProxy(int32 proxyId); - - /// Call MoveProxy as many times as you like, then when you are done - /// call UpdatePairs to finalized the proxy pairs (for your time step). - void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); - - /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. - void TouchProxy(int32 proxyId); - - /// Get the fat AABB for a proxy. - const b2AABB& GetFatAABB(int32 proxyId) const; - - /// Get user data from a proxy. Returns NULL if the id is invalid. - void* GetUserData(int32 proxyId) const; - - /// Test overlap of fat AABBs. - bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; - - /// Get the number of proxies. - int32 GetProxyCount() const; - - /// Update the pairs. This results in pair callbacks. This can only add pairs. - template - void UpdatePairs(T* callback); - - /// Query an AABB for overlapping proxies. The callback class - /// is called for each proxy that overlaps the supplied AABB. - template - void Query(T* callback, const b2AABB& aabb) const; - - /// Ray-cast against the proxies in the tree. This relies on the callback - /// to perform a exact ray-cast in the case were the proxy contains a shape. - /// The callback also performs the any collision filtering. This has performance - /// roughly equal to k * log(n), where k is the number of collisions and n is the - /// number of proxies in the tree. - /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). - /// @param callback a callback class that is called for each proxy that is hit by the ray. - template - void RayCast(T* callback, const b2RayCastInput& input) const; - - /// Get the height of the embedded tree. - int32 GetTreeHeight() const; - - /// Get the balance of the embedded tree. - int32 GetTreeBalance() const; - - /// Get the quality metric of the embedded tree. - float32 GetTreeQuality() const; - -private: - - friend class b2DynamicTree; - - void BufferMove(int32 proxyId); - void UnBufferMove(int32 proxyId); - - bool QueryCallback(int32 proxyId); - - b2DynamicTree m_tree; - - int32 m_proxyCount; - - int32* m_moveBuffer; - int32 m_moveCapacity; - int32 m_moveCount; - - b2Pair* m_pairBuffer; - int32 m_pairCapacity; - int32 m_pairCount; - - int32 m_queryProxyId; -}; - -/// This is used to sort pairs. -inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) -{ - if (pair1.proxyIdA < pair2.proxyIdA) - { - return true; - } - - if (pair1.proxyIdA == pair2.proxyIdA) - { - return pair1.proxyIdB < pair2.proxyIdB; - } - - return false; -} - -inline void* b2BroadPhase::GetUserData(int32 proxyId) const -{ - return m_tree.GetUserData(proxyId); -} - -inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const -{ - const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); - const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); - return b2TestOverlap(aabbA, aabbB); -} - -inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const -{ - return m_tree.GetFatAABB(proxyId); -} - -inline int32 b2BroadPhase::GetProxyCount() const -{ - return m_proxyCount; -} - -inline int32 b2BroadPhase::GetTreeHeight() const -{ - return m_tree.GetHeight(); -} - -inline int32 b2BroadPhase::GetTreeBalance() const -{ - return m_tree.GetMaxBalance(); -} - -inline float32 b2BroadPhase::GetTreeQuality() const -{ - return m_tree.GetAreaRatio(); -} - -template -void b2BroadPhase::UpdatePairs(T* callback) -{ - // Reset pair buffer - m_pairCount = 0; - - // Perform tree queries for all moving proxies. - for (int32 i = 0; i < m_moveCount; ++i) - { - m_queryProxyId = m_moveBuffer[i]; - if (m_queryProxyId == e_nullProxy) - { - continue; - } - - // We have to query the tree with the fat AABB so that - // we don't fail to create a pair that may touch later. - const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); - - // Query tree, create pairs and add them pair buffer. - m_tree.Query(this, fatAABB); - } - - // Reset move buffer - m_moveCount = 0; - - // Sort the pair buffer to expose duplicates. - std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); - - // Send the pairs back to the client. - int32 i = 0; - while (i < m_pairCount) - { - b2Pair* primaryPair = m_pairBuffer + i; - void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); - void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); - - callback->AddPair(userDataA, userDataB); - ++i; - - // Skip any duplicate pairs. - while (i < m_pairCount) - { - b2Pair* pair = m_pairBuffer + i; - if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) - { - break; - } - ++i; - } - } - - // Try to keep the tree balanced. - //m_tree.Rebalance(4); -} - -template -inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const -{ - m_tree.Query(callback, aabb); -} - -template -inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const -{ - m_tree.RayCast(callback, input); -} - -#endif diff --git a/external/box2d/Collision/b2CollideCircle.cpp b/external/box2d/Collision/b2CollideCircle.cpp deleted file mode 100644 index ed561eb04b..0000000000 --- a/external/box2d/Collision/b2CollideCircle.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include - -void b2CollideCircles( - b2Manifold* manifold, - const b2CircleShape* circleA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - - b2Vec2 pA = b2Mul(xfA, circleA->m_p); - b2Vec2 pB = b2Mul(xfB, circleB->m_p); - - b2Vec2 d = pB - pA; - float32 distSqr = b2Dot(d, d); - float32 rA = circleA->m_radius, rB = circleB->m_radius; - float32 radius = rA + rB; - if (distSqr > radius * radius) - { - return; - } - - manifold->type = b2Manifold::e_circles; - manifold->localPoint = circleA->m_p; - manifold->localNormal.SetZero(); - manifold->pointCount = 1; - - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; -} - -void b2CollidePolygonAndCircle( - b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - - // Compute circle position in the frame of the polygon. - b2Vec2 c = b2Mul(xfB, circleB->m_p); - b2Vec2 cLocal = b2MulT(xfA, c); - - // Find the min separating edge. - int32 normalIndex = 0; - float32 separation = -b2_maxFloat; - float32 radius = polygonA->m_radius + circleB->m_radius; - int32 vertexCount = polygonA->m_vertexCount; - const b2Vec2* vertices = polygonA->m_vertices; - const b2Vec2* normals = polygonA->m_normals; - - for (int32 i = 0; i < vertexCount; ++i) - { - float32 s = b2Dot(normals[i], cLocal - vertices[i]); - - if (s > radius) - { - // Early out. - return; - } - - if (s > separation) - { - separation = s; - normalIndex = i; - } - } - - // Vertices that subtend the incident face. - int32 vertIndex1 = normalIndex; - int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; - b2Vec2 v1 = vertices[vertIndex1]; - b2Vec2 v2 = vertices[vertIndex2]; - - // If the center is inside the polygon ... - if (separation < b2_epsilon) - { - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = normals[normalIndex]; - manifold->localPoint = 0.5f * (v1 + v2); - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - return; - } - - // Compute barycentric coordinates - float32 u1 = b2Dot(cLocal - v1, v2 - v1); - float32 u2 = b2Dot(cLocal - v2, v1 - v2); - if (u1 <= 0.0f) - { - if (b2DistanceSquared(cLocal, v1) > radius * radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = cLocal - v1; - manifold->localNormal.Normalize(); - manifold->localPoint = v1; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } - else if (u2 <= 0.0f) - { - if (b2DistanceSquared(cLocal, v2) > radius * radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = cLocal - v2; - manifold->localNormal.Normalize(); - manifold->localPoint = v2; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } - else - { - b2Vec2 faceCenter = 0.5f * (v1 + v2); - float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); - if (separation > radius) - { - return; - } - - manifold->pointCount = 1; - manifold->type = b2Manifold::e_faceA; - manifold->localNormal = normals[vertIndex1]; - manifold->localPoint = faceCenter; - manifold->points[0].localPoint = circleB->m_p; - manifold->points[0].id.key = 0; - } -} diff --git a/external/box2d/Collision/b2CollideEdge.cpp b/external/box2d/Collision/b2CollideEdge.cpp deleted file mode 100644 index 96ca71dccc..0000000000 --- a/external/box2d/Collision/b2CollideEdge.cpp +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include -#include -#include -#include - - -// 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 hasVertex3F = 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 (hasVertex3F) - { - 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 && hasVertex3F) - { - 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 (hasVertex3F) - { - 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 = 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 = 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 = 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 = 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); -} diff --git a/external/box2d/Collision/b2CollidePolygon.cpp b/external/box2d/Collision/b2CollidePolygon.cpp deleted file mode 100644 index be2518d966..0000000000 --- a/external/box2d/Collision/b2CollidePolygon.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -// Find the separation between poly1 and poly2 for a give edge normal on poly1. -static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - const b2Vec2* vertices1 = poly1->m_vertices; - const b2Vec2* normals1 = poly1->m_normals; - - int32 count2 = poly2->m_vertexCount; - const b2Vec2* vertices2 = poly2->m_vertices; - - b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); - - // Convert normal from poly1's frame into poly2's frame. - b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); - b2Vec2 normal1 = b2MulT(xf2.q, normal1World); - - // Find support vertex on poly2 for -normal. - int32 index = 0; - float32 minDot = b2_maxFloat; - - for (int32 i = 0; i < count2; ++i) - { - float32 dot = b2Dot(vertices2[i], normal1); - if (dot < minDot) - { - minDot = dot; - index = i; - } - } - - b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); - b2Vec2 v2 = b2Mul(xf2, vertices2[index]); - float32 separation = b2Dot(v2 - v1, normal1World); - return separation; -} - -// Find the max separation between poly1 and poly2 using edge normals from poly1. -static float32 b2FindMaxSeparation(int32* edgeIndex, - const b2PolygonShape* poly1, const b2Transform& xf1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - int32 count1 = poly1->m_vertexCount; - const b2Vec2* normals1 = poly1->m_normals; - - // Vector pointing from the centroid of poly1 to the centroid of poly2. - b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); - b2Vec2 dLocal1 = b2MulT(xf1.q, d); - - // Find edge normal on poly1 that has the largest projection onto d. - int32 edge = 0; - float32 maxDot = -b2_maxFloat; - for (int32 i = 0; i < count1; ++i) - { - float32 dot = b2Dot(normals1[i], dLocal1); - if (dot > maxDot) - { - maxDot = dot; - edge = i; - } - } - - // Get the separation for the edge normal. - float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); - - // Check the separation for the previous edge normal. - int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; - float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); - - // Check the separation for the next edge normal. - int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; - float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); - - // Find the best edge and the search direction. - int32 bestEdge; - float32 bestSeparation; - int32 increment; - if (sPrev > s && sPrev > sNext) - { - increment = -1; - bestEdge = prevEdge; - bestSeparation = sPrev; - } - else if (sNext > s) - { - increment = 1; - bestEdge = nextEdge; - bestSeparation = sNext; - } - else - { - *edgeIndex = edge; - return s; - } - - // Perform a local search for the best edge normal. - for ( ; ; ) - { - if (increment == -1) - edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; - else - edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; - - s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); - - if (s > bestSeparation) - { - bestEdge = edge; - bestSeparation = s; - } - else - { - break; - } - } - - *edgeIndex = bestEdge; - return bestSeparation; -} - -static void b2FindIncidentEdge(b2ClipVertex c[2], - const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, - const b2PolygonShape* poly2, const b2Transform& xf2) -{ - const b2Vec2* normals1 = poly1->m_normals; - - int32 count2 = poly2->m_vertexCount; - const b2Vec2* vertices2 = poly2->m_vertices; - const b2Vec2* normals2 = poly2->m_normals; - - b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); - - // Get the normal of the reference edge in poly2's frame. - b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); - - // Find the incident edge on poly2. - int32 index = 0; - float32 minDot = b2_maxFloat; - for (int32 i = 0; i < count2; ++i) - { - float32 dot = b2Dot(normal1, normals2[i]); - if (dot < minDot) - { - minDot = dot; - index = i; - } - } - - // Build the clip vertices for the incident edge. - int32 i1 = index; - int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; - - c[0].v = b2Mul(xf2, vertices2[i1]); - c[0].id.cf.indexA = (uint8)edge1; - c[0].id.cf.indexB = (uint8)i1; - c[0].id.cf.typeA = b2ContactFeature::e_face; - c[0].id.cf.typeB = b2ContactFeature::e_vertex; - - c[1].v = b2Mul(xf2, vertices2[i2]); - c[1].id.cf.indexA = (uint8)edge1; - c[1].id.cf.indexB = (uint8)i2; - c[1].id.cf.typeA = b2ContactFeature::e_face; - c[1].id.cf.typeB = b2ContactFeature::e_vertex; -} - -// Find edge normal of max separation on A - return if separating axis is found -// Find edge normal of max separation on B - return if separation axis is found -// Choose reference edge as min(minA, minB) -// Find incident edge -// Clip - -// The normal points from 1 to 2 -void b2CollidePolygons(b2Manifold* manifold, - const b2PolygonShape* polyA, const b2Transform& xfA, - const b2PolygonShape* polyB, const b2Transform& xfB) -{ - manifold->pointCount = 0; - float32 totalRadius = polyA->m_radius + polyB->m_radius; - - int32 edgeA = 0; - float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); - if (separationA > totalRadius) - return; - - int32 edgeB = 0; - float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); - if (separationB > totalRadius) - return; - - const b2PolygonShape* poly1; // reference polygon - const b2PolygonShape* poly2; // incident polygon - b2Transform xf1, xf2; - int32 edge1; // reference edge - uint8 flip; - const float32 k_relativeTol = 0.98f; - const float32 k_absoluteTol = 0.001f; - - if (separationB > k_relativeTol * separationA + k_absoluteTol) - { - poly1 = polyB; - poly2 = polyA; - xf1 = xfB; - xf2 = xfA; - edge1 = edgeB; - manifold->type = b2Manifold::e_faceB; - flip = 1; - } - else - { - poly1 = polyA; - poly2 = polyB; - xf1 = xfA; - xf2 = xfB; - edge1 = edgeA; - manifold->type = b2Manifold::e_faceA; - flip = 0; - } - - b2ClipVertex incidentEdge[2]; - b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); - - int32 count1 = poly1->m_vertexCount; - const b2Vec2* vertices1 = poly1->m_vertices; - - int32 iv1 = edge1; - int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; - - b2Vec2 v11 = vertices1[iv1]; - b2Vec2 v12 = vertices1[iv2]; - - b2Vec2 localTangent = v12 - v11; - localTangent.Normalize(); - - b2Vec2 localNormal = b2Cross(localTangent, 1.0f); - b2Vec2 planePoint = 0.5f * (v11 + v12); - - b2Vec2 tangent = b2Mul(xf1.q, localTangent); - b2Vec2 normal = b2Cross(tangent, 1.0f); - - v11 = b2Mul(xf1, v11); - v12 = b2Mul(xf1, v12); - - // Face offset. - float32 frontOffset = b2Dot(normal, v11); - - // Side offsets, extended by polytope skin thickness. - float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; - float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; - - // Clip incident edge against extruded edge1 side edges. - b2ClipVertex clipPoints1[2]; - b2ClipVertex clipPoints2[2]; - int np; - - // Clip to box side 1 - np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); - - if (np < 2) - return; - - // Clip to negative box side 1 - np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); - - if (np < 2) - { - return; - } - - // Now clipPoints2 contains the clipped points. - manifold->localNormal = localNormal; - manifold->localPoint = planePoint; - - int32 pointCount = 0; - for (int32 i = 0; i < b2_maxManifoldPoints; ++i) - { - float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; - - if (separation <= totalRadius) - { - b2ManifoldPoint* cp = manifold->points + pointCount; - cp->localPoint = b2MulT(xf2, clipPoints2[i].v); - cp->id = clipPoints2[i].id; - if (flip) - { - // Swap features - b2ContactFeature cf = cp->id.cf; - cp->id.cf.indexA = cf.indexB; - cp->id.cf.indexB = cf.indexA; - cp->id.cf.typeA = cf.typeB; - cp->id.cf.typeB = cf.typeA; - } - ++pointCount; - } - } - - manifold->pointCount = pointCount; -} diff --git a/external/box2d/Collision/b2Collision.cpp b/external/box2d/Collision/b2Collision.cpp deleted file mode 100644 index 2dd5ff0ab6..0000000000 --- a/external/box2d/Collision/b2Collision.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include - -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 = 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; -} diff --git a/external/box2d/Collision/b2Collision.h b/external/box2d/Collision/b2Collision.h deleted file mode 100644 index 2e7386232b..0000000000 --- a/external/box2d/Collision/b2Collision.h +++ /dev/null @@ -1,276 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_COLLISION_H -#define B2_COLLISION_H - -#include -#include - -/// @file -/// Structures and functions used for computing contact points, distance -/// queries, and TOI queries. - -class b2Shape; -class b2CircleShape; -class b2EdgeShape; -class b2PolygonShape; - -const uint8 b2_nullFeature = UCHAR_MAX; - -/// The features that intersect to form the contact point -/// This must be 4 bytes or less. -struct b2ContactFeature -{ - enum Type - { - e_vertex = 0, - e_face = 1 - }; - - uint8 indexA; ///< Feature index on shapeA - uint8 indexB; ///< Feature index on shapeB - uint8 typeA; ///< The feature type on shapeA - uint8 typeB; ///< The feature type on shapeB -}; - -/// Contact ids to facilitate warm starting. -union b2ContactID -{ - b2ContactFeature cf; - uint32 key; ///< Used to quickly compare contact ids. -}; - -/// A manifold point is a contact point belonging to a contact -/// manifold. It holds details related to the geometry and dynamics -/// of the contact points. -/// The local point usage depends on the manifold type: -/// -e_circles: the local center of circleB -/// -e_faceA: the local center of cirlceB or the clip point of polygonB -/// -e_faceB: the clip point of polygonA -/// This structure is stored across time steps, so we keep it small. -/// Note: the impulses are used for internal caching and may not -/// provide reliable contact forces, especially for high speed collisions. -struct b2ManifoldPoint -{ - b2Vec2 localPoint; ///< usage depends on manifold type - float32 normalImpulse; ///< the non-penetration impulse - float32 tangentImpulse; ///< the friction impulse - b2ContactID id; ///< uniquely identifies a contact point between two shapes -}; - -/// A manifold for two touching convex shapes. -/// Box2D supports multiple types of contact: -/// - clip point versus plane with radius -/// - point versus point with radius (circles) -/// The local point usage depends on the manifold type: -/// -e_circles: the local center of circleA -/// -e_faceA: the center of faceA -/// -e_faceB: the center of faceB -/// Similarly the local normal usage: -/// -e_circles: not used -/// -e_faceA: the normal on polygonA -/// -e_faceB: the normal on polygonB -/// We store contacts in this way so that position correction can -/// account for movement, which is critical for continuous physics. -/// All contact scenarios must be expressed in one of these types. -/// This structure is stored across time steps, so we keep it small. -struct b2Manifold -{ - enum Type - { - e_circles, - e_faceA, - e_faceB - }; - - b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact - b2Vec2 localNormal; ///< not use for Type::e_points - b2Vec2 localPoint; ///< usage depends on manifold type - Type type; - int32 pointCount; ///< the number of manifold points -}; - -/// This is used to compute the current state of a contact manifold. -struct b2WorldManifold -{ - /// Evaluate the manifold with supplied transforms. This assumes - /// modest motion from the original state. This does not change the - /// point count, impulses, etc. The radii must come from the shapes - /// that generated the manifold. - void Initialize(const b2Manifold* manifold, - const b2Transform& xfA, float32 radiusA, - const b2Transform& xfB, float32 radiusB); - - b2Vec2 normal; ///< world vector pointing from A to B - b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) -}; - -/// This is used for determining the state of contact points. -enum b2PointState -{ - b2_nullState, ///< point does not exist - b2_addState, ///< point was added in the update - b2_persistState, ///< point persisted across the update - b2_removeState ///< point was removed in the update -}; - -/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 -/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. -void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], - const b2Manifold* manifold1, const b2Manifold* manifold2); - -/// Used for computing contact manifolds. -struct b2ClipVertex -{ - b2Vec2 v; - b2ContactID id; -}; - -/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). -struct b2RayCastInput -{ - b2Vec2 p1, p2; - float32 maxFraction; -}; - -/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 -/// come from b2RayCastInput. -struct b2RayCastOutput -{ - b2Vec2 normal; - float32 fraction; -}; - -/// An axis aligned bounding box. -struct b2AABB -{ - /// Verify that the bounds are sorted. - bool IsValid() const; - - /// Get the center of the AABB. - b2Vec2 GetCenter() const - { - return 0.5f * (lowerBound + upperBound); - } - - /// Get the extents of the AABB (half-widths). - b2Vec2 GetExtents() const - { - return 0.5f * (upperBound - lowerBound); - } - - /// Get the perimeter length - float32 GetPerimeter() const - { - float32 wx = upperBound.x - lowerBound.x; - float32 wy = upperBound.y - lowerBound.y; - return 2.0f * (wx + wy); - } - - /// Combine an AABB into this one. - void Combine(const b2AABB& aabb) - { - lowerBound = b2Min(lowerBound, aabb.lowerBound); - upperBound = b2Max(upperBound, aabb.upperBound); - } - - /// Combine two AABBs into this one. - void Combine(const b2AABB& aabb1, const b2AABB& aabb2) - { - lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); - upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); - } - - /// Does this aabb contain the provided AABB. - bool Contains(const b2AABB& aabb) const - { - bool result = true; - result = result && lowerBound.x <= aabb.lowerBound.x; - result = result && lowerBound.y <= aabb.lowerBound.y; - result = result && aabb.upperBound.x <= upperBound.x; - result = result && aabb.upperBound.y <= upperBound.y; - return result; - } - - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; - - b2Vec2 lowerBound; ///< the lower vertex - b2Vec2 upperBound; ///< the upper vertex -}; - -/// Compute the collision manifold between two circles. -void b2CollideCircles(b2Manifold* manifold, - const b2CircleShape* circleA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between a polygon and a circle. -void b2CollidePolygonAndCircle(b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between two polygons. -void b2CollidePolygons(b2Manifold* manifold, - const b2PolygonShape* polygonA, const b2Transform& xfA, - const b2PolygonShape* polygonB, const b2Transform& xfB); - -/// Compute the collision manifold between an edge and a circle. -void b2CollideEdgeAndCircle(b2Manifold* manifold, - const b2EdgeShape* polygonA, const b2Transform& xfA, - const b2CircleShape* circleB, const b2Transform& xfB); - -/// Compute the collision manifold between an edge and a circle. -void b2CollideEdgeAndPolygon(b2Manifold* manifold, - const b2EdgeShape* edgeA, const b2Transform& xfA, - const b2PolygonShape* circleB, const b2Transform& xfB); - -/// Clipping for contact manifolds. -int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], - const b2Vec2& normal, float32 offset, int32 vertexIndexA); - -/// Determine if two generic shapes overlap. -bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, - const b2Shape* shapeB, int32 indexB, - const b2Transform& xfA, const b2Transform& xfB); - -// ---------------- Inline Functions ------------------------------------------ - -inline bool b2AABB::IsValid() const -{ - b2Vec2 d = upperBound - lowerBound; - bool valid = d.x >= 0.0f && d.y >= 0.0f; - valid = valid && lowerBound.IsValid() && upperBound.IsValid(); - return valid; -} - -inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) -{ - b2Vec2 d1, d2; - d1 = b.lowerBound - a.upperBound; - d2 = a.lowerBound - b.upperBound; - - if (d1.x > 0.0f || d1.y > 0.0f) - return false; - - if (d2.x > 0.0f || d2.y > 0.0f) - return false; - - return true; -} - -#endif diff --git a/external/box2d/Collision/b2Distance.cpp b/external/box2d/Collision/b2Distance.cpp deleted file mode 100644 index ac67d3be43..0000000000 --- a/external/box2d/Collision/b2Distance.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include -#include -#include - -// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. -int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; - -void b2DistanceProxy::Set(const b2Shape* shape, int32 index) -{ - switch (shape->GetType()) - { - case b2Shape::e_circle: - { - const b2CircleShape* circle = (b2CircleShape*)shape; - m_vertices = &circle->m_p; - m_count = 1; - m_radius = circle->m_radius; - } - break; - - case b2Shape::e_polygon: - { - const b2PolygonShape* polygon = (b2PolygonShape*)shape; - m_vertices = polygon->m_vertices; - m_count = polygon->m_vertexCount; - m_radius = polygon->m_radius; - } - break; - - case b2Shape::e_chain: - { - const b2ChainShape* chain = (b2ChainShape*)shape; - b2Assert(0 <= index && index < chain->m_count); - - m_buffer[0] = chain->m_vertices[index]; - if (index + 1 < chain->m_count) - { - m_buffer[1] = chain->m_vertices[index + 1]; - } - else - { - m_buffer[1] = chain->m_vertices[0]; - } - - m_vertices = m_buffer; - m_count = 2; - m_radius = chain->m_radius; - } - break; - - case b2Shape::e_edge: - { - const b2EdgeShape* edge = (b2EdgeShape*)shape; - m_vertices = &edge->m_vertex1; - m_count = 2; - m_radius = edge->m_radius; - } - break; - - default: - b2Assert(false); - } -} - - -struct b2SimplexVertex -{ - b2Vec2 wA; // support point in proxyA - b2Vec2 wB; // support point in proxyB - b2Vec2 w; // wB - wA - float32 a; // barycentric coordinate for closest point - int32 indexA; // wA index - int32 indexB; // wB index -}; - -struct b2Simplex -{ - void ReadCache( const b2SimplexCache* cache, - const b2DistanceProxy* proxyA, const b2Transform& transformA, - const b2DistanceProxy* proxyB, const b2Transform& transformB) - { - b2Assert(cache->count <= 3); - - // Copy data from cache. - m_count = cache->count; - b2SimplexVertex* vertices = &m_v1; - for (int32 i = 0; i < m_count; ++i) - { - b2SimplexVertex* v = vertices + i; - v->indexA = cache->indexA[i]; - v->indexB = cache->indexB[i]; - b2Vec2 wALocal = proxyA->GetVertex(v->indexA); - b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); - v->wA = b2Mul(transformA, wALocal); - v->wB = b2Mul(transformB, wBLocal); - v->w = v->wB - v->wA; - v->a = 0.0f; - } - - // Compute the new simplex metric, if it is substantially different than - // old metric then flush the simplex. - if (m_count > 1) - { - float32 metric1 = cache->metric; - float32 metric2 = GetMetric(); - if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) - { - // Reset the simplex. - m_count = 0; - } - } - - // If the cache is empty or invalid ... - if (m_count == 0) - { - b2SimplexVertex* v = vertices + 0; - v->indexA = 0; - v->indexB = 0; - b2Vec2 wALocal = proxyA->GetVertex(0); - b2Vec2 wBLocal = proxyB->GetVertex(0); - v->wA = b2Mul(transformA, wALocal); - v->wB = b2Mul(transformB, wBLocal); - v->w = v->wB - v->wA; - m_count = 1; - } - } - - void WriteCache(b2SimplexCache* cache) const - { - cache->metric = GetMetric(); - cache->count = uint16(m_count); - const b2SimplexVertex* vertices = &m_v1; - for (int32 i = 0; i < m_count; ++i) - { - cache->indexA[i] = uint8(vertices[i].indexA); - cache->indexB[i] = uint8(vertices[i].indexB); - } - } - - b2Vec2 GetSearchDirection() const - { - switch (m_count) - { - case 1: - return -m_v1.w; - - case 2: - { - b2Vec2 e12 = m_v2.w - m_v1.w; - float32 sgn = b2Cross(e12, -m_v1.w); - if (sgn > 0.0f) - { - // Origin is left of e12. - return b2Cross(1.0f, e12); - } - else - { - // Origin is right of e12. - return b2Cross(e12, 1.0f); - } - } - - default: - b2Assert(false); - return b2Vec2_zero; - } - } - - b2Vec2 GetClosestPoint() const - { - switch (m_count) - { - case 0: - b2Assert(false); - return b2Vec2_zero; - - case 1: - return m_v1.w; - - case 2: - return m_v1.a * m_v1.w + m_v2.a * m_v2.w; - - case 3: - return b2Vec2_zero; - - default: - b2Assert(false); - return b2Vec2_zero; - } - } - - void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const - { - switch (m_count) - { - case 0: - b2Assert(false); - break; - - case 1: - *pA = m_v1.wA; - *pB = m_v1.wB; - break; - - case 2: - *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; - *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; - break; - - case 3: - *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; - *pB = *pA; - break; - - default: - b2Assert(false); - break; - } - } - - float32 GetMetric() const - { - switch (m_count) - { - case 0: - b2Assert(false); - return 0.0; - - case 1: - return 0.0f; - - case 2: - return b2Distance(m_v1.w, m_v2.w); - - case 3: - return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); - - default: - b2Assert(false); - return 0.0f; - } - } - - void Solve2(); - void Solve3(); - - b2SimplexVertex m_v1, m_v2, m_v3; - int32 m_count; -}; - - -// Solve a line segment using barycentric coordinates. -// -// p = a1 * w1 + a2 * w2 -// a1 + a2 = 1 -// -// The vector from the origin to the closest point on the line is -// perpendicular to the line. -// e12 = w2 - w1 -// dot(p, e) = 0 -// a1 * dot(w1, e) + a2 * dot(w2, e) = 0 -// -// 2-by-2 linear system -// [1 1 ][a1] = [1] -// [w1.e12 w2.e12][a2] = [0] -// -// Define -// d12_1 = dot(w2, e12) -// d12_2 = -dot(w1, e12) -// d12 = d12_1 + d12_2 -// -// Solution -// a1 = d12_1 / d12 -// a2 = d12_2 / d12 -void b2Simplex::Solve2() -{ - b2Vec2 w1 = m_v1.w; - b2Vec2 w2 = m_v2.w; - b2Vec2 e12 = w2 - w1; - - // w1 region - float32 d12_2 = -b2Dot(w1, e12); - if (d12_2 <= 0.0f) - { - // a2 <= 0, so we clamp it to 0 - m_v1.a = 1.0f; - m_count = 1; - return; - } - - // w2 region - float32 d12_1 = b2Dot(w2, e12); - if (d12_1 <= 0.0f) - { - // a1 <= 0, so we clamp it to 0 - m_v2.a = 1.0f; - m_count = 1; - m_v1 = m_v2; - return; - } - - // Must be in e12 region. - float32 inv_d12 = 1.0f / (d12_1 + d12_2); - m_v1.a = d12_1 * inv_d12; - m_v2.a = d12_2 * inv_d12; - m_count = 2; -} - -// Possible regions: -// - points[2] -// - edge points[0]-points[2] -// - edge points[1]-points[2] -// - inside the triangle -void b2Simplex::Solve3() -{ - b2Vec2 w1 = m_v1.w; - b2Vec2 w2 = m_v2.w; - b2Vec2 w3 = m_v3.w; - - // Edge12 - // [1 1 ][a1] = [1] - // [w1.e12 w2.e12][a2] = [0] - // a3 = 0 - b2Vec2 e12 = w2 - w1; - float32 w1e12 = b2Dot(w1, e12); - float32 w2e12 = b2Dot(w2, e12); - float32 d12_1 = w2e12; - float32 d12_2 = -w1e12; - - // Edge13 - // [1 1 ][a1] = [1] - // [w1.e13 w3.e13][a3] = [0] - // a2 = 0 - b2Vec2 e13 = w3 - w1; - float32 w1e13 = b2Dot(w1, e13); - float32 w3e13 = b2Dot(w3, e13); - float32 d13_1 = w3e13; - float32 d13_2 = -w1e13; - - // Edge23 - // [1 1 ][a2] = [1] - // [w2.e23 w3.e23][a3] = [0] - // a1 = 0 - b2Vec2 e23 = w3 - w2; - float32 w2e23 = b2Dot(w2, e23); - float32 w3e23 = b2Dot(w3, e23); - float32 d23_1 = w3e23; - float32 d23_2 = -w2e23; - - // Triangle123 - float32 n123 = b2Cross(e12, e13); - - float32 d123_1 = n123 * b2Cross(w2, w3); - float32 d123_2 = n123 * b2Cross(w3, w1); - float32 d123_3 = n123 * b2Cross(w1, w2); - - // w1 region - if (d12_2 <= 0.0f && d13_2 <= 0.0f) - { - m_v1.a = 1.0f; - m_count = 1; - return; - } - - // e12 - if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) - { - float32 inv_d12 = 1.0f / (d12_1 + d12_2); - m_v1.a = d12_1 * inv_d12; - m_v2.a = d12_2 * inv_d12; - m_count = 2; - return; - } - - // e13 - if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) - { - float32 inv_d13 = 1.0f / (d13_1 + d13_2); - m_v1.a = d13_1 * inv_d13; - m_v3.a = d13_2 * inv_d13; - m_count = 2; - m_v2 = m_v3; - return; - } - - // w2 region - if (d12_1 <= 0.0f && d23_2 <= 0.0f) - { - m_v2.a = 1.0f; - m_count = 1; - m_v1 = m_v2; - return; - } - - // w3 region - if (d13_1 <= 0.0f && d23_1 <= 0.0f) - { - m_v3.a = 1.0f; - m_count = 1; - m_v1 = m_v3; - return; - } - - // e23 - if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) - { - float32 inv_d23 = 1.0f / (d23_1 + d23_2); - m_v2.a = d23_1 * inv_d23; - m_v3.a = d23_2 * inv_d23; - m_count = 2; - m_v1 = m_v3; - return; - } - - // Must be in triangle123 - float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); - m_v1.a = d123_1 * inv_d123; - m_v2.a = d123_2 * inv_d123; - m_v3.a = d123_3 * inv_d123; - m_count = 3; -} - -void b2Distance(b2DistanceOutput* output, - b2SimplexCache* cache, - const b2DistanceInput* input) -{ - ++b2_gjkCalls; - - const b2DistanceProxy* proxyA = &input->proxyA; - const b2DistanceProxy* proxyB = &input->proxyB; - - b2Transform transformA = input->transformA; - b2Transform transformB = input->transformB; - - // Initialize the simplex. - b2Simplex simplex; - simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); - - // Get simplex vertices as an array. - b2SimplexVertex* vertices = &simplex.m_v1; - const int32 k_maxIters = 20; - - // These store the vertices of the last simplex so that we - // can check for duplicates and prevent cycling. - int32 saveA[3], saveB[3]; - int32 saveCount = 0; - - b2Vec2 closestPoint = simplex.GetClosestPoint(); - float32 distanceSqr1 = closestPoint.LengthSquared(); - float32 distanceSqr2 = distanceSqr1; - - // Main iteration loop. - int32 iter = 0; - while (iter < k_maxIters) - { - // Copy simplex so we can identify duplicates. - saveCount = simplex.m_count; - for (int32 i = 0; i < saveCount; ++i) - { - saveA[i] = vertices[i].indexA; - saveB[i] = vertices[i].indexB; - } - - switch (simplex.m_count) - { - case 1: - break; - - case 2: - simplex.Solve2(); - break; - - case 3: - simplex.Solve3(); - break; - - default: - b2Assert(false); - } - - // If we have 3 points, then the origin is in the corresponding triangle. - if (simplex.m_count == 3) - { - break; - } - - // Compute closest point. - b2Vec2 p = simplex.GetClosestPoint(); - distanceSqr2 = p.LengthSquared(); - - // Ensure progress - if (distanceSqr2 >= distanceSqr1) - { - //break; - } - distanceSqr1 = distanceSqr2; - - // Get search direction. - b2Vec2 d = simplex.GetSearchDirection(); - - // Ensure the search direction is numerically fit. - if (d.LengthSquared() < b2_epsilon * b2_epsilon) - { - // The origin is probably contained by a line segment - // or triangle. Thus the shapes are overlapped. - - // We can't return zero here even though there may be overlap. - // In case the simplex is a point, segment, or triangle it is difficult - // to determine if the origin is contained in the CSO or very close to it. - break; - } - - // Compute a tentative new simplex vertex using support points. - b2SimplexVertex* vertex = vertices + simplex.m_count; - vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); - vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); - b2Vec2 wBLocal; - vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); - vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); - vertex->w = vertex->wB - vertex->wA; - - // Iteration count is equated to the number of support point calls. - ++iter; - ++b2_gjkIters; - - // Check for duplicate support points. This is the main termination criteria. - bool duplicate = false; - for (int32 i = 0; i < saveCount; ++i) - { - if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) - { - duplicate = true; - break; - } - } - - // If we found a duplicate support point we must exit to avoid cycling. - if (duplicate) - { - break; - } - - // New vertex is ok and needed. - ++simplex.m_count; - } - - b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); - - // Prepare output. - simplex.GetWitnessPoints(&output->pointA, &output->pointB); - output->distance = b2Distance(output->pointA, output->pointB); - output->iterations = iter; - - // Cache the simplex. - simplex.WriteCache(cache); - - // Apply radii if requested. - if (input->useRadii) - { - float32 rA = proxyA->m_radius; - float32 rB = proxyB->m_radius; - - if (output->distance > rA + rB && output->distance > b2_epsilon) - { - // Shapes are still no overlapped. - // Move the witness points to the outer surface. - output->distance -= rA + rB; - b2Vec2 normal = output->pointB - output->pointA; - normal.Normalize(); - output->pointA += rA * normal; - output->pointB -= rB * normal; - } - else - { - // Shapes are overlapped when radii are considered. - // Move the witness points to the middle. - b2Vec2 p = 0.5f * (output->pointA + output->pointB); - output->pointA = p; - output->pointB = p; - output->distance = 0.0f; - } - } -} diff --git a/external/box2d/Collision/b2Distance.h b/external/box2d/Collision/b2Distance.h deleted file mode 100644 index d598b7339d..0000000000 --- a/external/box2d/Collision/b2Distance.h +++ /dev/null @@ -1,141 +0,0 @@ - -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_DISTANCE_H -#define B2_DISTANCE_H - -#include - -class b2Shape; - -/// A distance proxy is used by the GJK algorithm. -/// It encapsulates any shape. -struct b2DistanceProxy -{ - b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} - - /// Initialize the proxy using the given shape. The shape - /// must remain in scope while the proxy is in use. - void Set(const b2Shape* shape, int32 index); - - /// Get the supporting vertex index in the given direction. - int32 GetSupport(const b2Vec2& d) const; - - /// Get the supporting vertex in the given direction. - const b2Vec2& GetSupportVertex(const b2Vec2& d) const; - - /// Get the vertex count. - int32 GetVertexCount() const; - - /// Get a vertex by index. Used by b2Distance. - const b2Vec2& GetVertex(int32 index) const; - - b2Vec2 m_buffer[2]; - const b2Vec2* m_vertices; - int32 m_count; - float32 m_radius; -}; - -/// Used to warm start b2Distance. -/// Set count to zero on first call. -struct b2SimplexCache -{ - float32 metric; ///< length or area - uint16 count; - uint8 indexA[3]; ///< vertices on shape A - uint8 indexB[3]; ///< vertices on shape B -}; - -/// Input for b2Distance. -/// You have to option to use the shape radii -/// in the computation. Even -struct b2DistanceInput -{ - b2DistanceProxy proxyA; - b2DistanceProxy proxyB; - b2Transform transformA; - b2Transform transformB; - bool useRadii; -}; - -/// Output for b2Distance. -struct b2DistanceOutput -{ - b2Vec2 pointA; ///< closest point on shapeA - b2Vec2 pointB; ///< closest point on shapeB - float32 distance; - int32 iterations; ///< number of GJK iterations used -}; - -/// Compute the closest points between two shapes. Supports any combination of: -/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. -/// On the first call set b2SimplexCache.count to zero. -void b2Distance(b2DistanceOutput* output, - b2SimplexCache* cache, - const b2DistanceInput* input); - - -////////////////////////////////////////////////////////////////////////// - -inline int32 b2DistanceProxy::GetVertexCount() const -{ - return m_count; -} - -inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const -{ - b2Assert(0 <= index && index < m_count); - return m_vertices[index]; -} - -inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const -{ - int32 bestIndex = 0; - float32 bestValue = b2Dot(m_vertices[0], d); - for (int32 i = 1; i < m_count; ++i) - { - float32 value = b2Dot(m_vertices[i], d); - if (value > bestValue) - { - bestIndex = i; - bestValue = value; - } - } - - return bestIndex; -} - -inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const -{ - int32 bestIndex = 0; - float32 bestValue = b2Dot(m_vertices[0], d); - for (int32 i = 1; i < m_count; ++i) - { - float32 value = b2Dot(m_vertices[i], d); - if (value > bestValue) - { - bestIndex = i; - bestValue = value; - } - } - - return m_vertices[bestIndex]; -} - -#endif diff --git a/external/box2d/Collision/b2DynamicTree.cpp b/external/box2d/Collision/b2DynamicTree.cpp deleted file mode 100644 index d1d53297e2..0000000000 --- a/external/box2d/Collision/b2DynamicTree.cpp +++ /dev/null @@ -1,775 +0,0 @@ -/* -* Copyright (c) 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 -#include -#ifndef SHP -#include -#else -#include -#endif -using namespace std; - - -b2DynamicTree::b2DynamicTree() -{ - m_root = b2_nullNode; - - m_nodeCapacity = 16; - m_nodeCount = 0; - m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); - memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); - - // Build a linked list for the free list. - for (int32 i = 0; i < m_nodeCapacity - 1; ++i) - { - m_nodes[i].next = i + 1; - m_nodes[i].height = -1; - } - m_nodes[m_nodeCapacity-1].next = b2_nullNode; - m_nodes[m_nodeCapacity-1].height = -1; - m_freeList = 0; - - m_path = 0; - - m_insertionCount = 0; -} - -b2DynamicTree::~b2DynamicTree() -{ - // This frees the entire tree in one shot. - b2Free(m_nodes); -} - -// Allocate a node from the pool. Grow the pool if necessary. -int32 b2DynamicTree::AllocateNode() -{ - // Expand the node pool as needed. - if (m_freeList == b2_nullNode) - { - b2Assert(m_nodeCount == m_nodeCapacity); - - // The free list is empty. Rebuild a bigger pool. - b2TreeNode* oldNodes = m_nodes; - m_nodeCapacity *= 2; - m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); - memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); - b2Free(oldNodes); - - // Build a linked list for the free list. The parent - // pointer becomes the "next" pointer. - for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) - { - m_nodes[i].next = i + 1; - m_nodes[i].height = -1; - } - m_nodes[m_nodeCapacity-1].next = b2_nullNode; - m_nodes[m_nodeCapacity-1].height = -1; - m_freeList = m_nodeCount; - } - - // Peel a node off the free list. - int32 nodeId = m_freeList; - m_freeList = m_nodes[nodeId].next; - m_nodes[nodeId].parent = b2_nullNode; - m_nodes[nodeId].child1 = b2_nullNode; - m_nodes[nodeId].child2 = b2_nullNode; - m_nodes[nodeId].height = 0; - m_nodes[nodeId].userData = NULL; - ++m_nodeCount; - return nodeId; -} - -// Return a node to the pool. -void b2DynamicTree::FreeNode(int32 nodeId) -{ - b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); - b2Assert(0 < m_nodeCount); - m_nodes[nodeId].next = m_freeList; - m_nodes[nodeId].height = -1; - m_freeList = nodeId; - --m_nodeCount; -} - -// Create a proxy in the tree as a leaf node. We return the index -// of the node instead of a pointer so that we can grow -// the node pool. -int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) -{ - int32 proxyId = AllocateNode(); - - // Fatten the aabb. - b2Vec2 r(b2_aabbExtension, b2_aabbExtension); - m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; - m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; - m_nodes[proxyId].userData = userData; - m_nodes[proxyId].height = 0; - - InsertLeaf(proxyId); - - return proxyId; -} - -void b2DynamicTree::DestroyProxy(int32 proxyId) -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - b2Assert(m_nodes[proxyId].IsLeaf()); - - RemoveLeaf(proxyId); - FreeNode(proxyId); -} - -bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - - b2Assert(m_nodes[proxyId].IsLeaf()); - - if (m_nodes[proxyId].aabb.Contains(aabb)) - { - return false; - } - - RemoveLeaf(proxyId); - - // Extend AABB. - b2AABB b = aabb; - b2Vec2 r(b2_aabbExtension, b2_aabbExtension); - b.lowerBound = b.lowerBound - r; - b.upperBound = b.upperBound + r; - - // Predict AABB displacement. - b2Vec2 d = b2_aabbMultiplier * displacement; - - if (d.x < 0.0f) - { - b.lowerBound.x += d.x; - } - else - { - b.upperBound.x += d.x; - } - - if (d.y < 0.0f) - { - b.lowerBound.y += d.y; - } - else - { - b.upperBound.y += d.y; - } - - m_nodes[proxyId].aabb = b; - - InsertLeaf(proxyId); - return true; -} - -void b2DynamicTree::InsertLeaf(int32 leaf) -{ - ++m_insertionCount; - - if (m_root == b2_nullNode) - { - m_root = leaf; - m_nodes[m_root].parent = b2_nullNode; - return; - } - - // Find the best sibling for this node - b2AABB leafAABB = m_nodes[leaf].aabb; - int32 index = m_root; - while (m_nodes[index].IsLeaf() == false) - { - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - float32 area = m_nodes[index].aabb.GetPerimeter(); - - b2AABB combinedAABB; - combinedAABB.Combine(m_nodes[index].aabb, leafAABB); - float32 combinedArea = combinedAABB.GetPerimeter(); - - // Cost of creating a new parent for this node and the new leaf - float32 cost = 2.0f * combinedArea; - - // Minimum cost of pushing the leaf further down the tree - float32 inheritanceCost = 2.0f * (combinedArea - area); - - // Cost of descending into child1 - float32 cost1; - if (m_nodes[child1].IsLeaf()) - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child1].aabb); - cost1 = aabb.GetPerimeter() + inheritanceCost; - } - else - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child1].aabb); - float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); - float32 newArea = aabb.GetPerimeter(); - cost1 = (newArea - oldArea) + inheritanceCost; - } - - // Cost of descending into child2 - float32 cost2; - if (m_nodes[child2].IsLeaf()) - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child2].aabb); - cost2 = aabb.GetPerimeter() + inheritanceCost; - } - else - { - b2AABB aabb; - aabb.Combine(leafAABB, m_nodes[child2].aabb); - float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); - float32 newArea = aabb.GetPerimeter(); - cost2 = newArea - oldArea + inheritanceCost; - } - - // Descend according to the minimum cost. - if (cost < cost1 && cost < cost2) - { - break; - } - - // Descend - if (cost1 < cost2) - { - index = child1; - } - else - { - index = child2; - } - } - - int32 sibling = index; - - // Create a new parent. - int32 oldParent = m_nodes[sibling].parent; - int32 newParent = AllocateNode(); - m_nodes[newParent].parent = oldParent; - m_nodes[newParent].userData = NULL; - m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); - m_nodes[newParent].height = m_nodes[sibling].height + 1; - - if (oldParent != b2_nullNode) - { - // The sibling was not the root. - if (m_nodes[oldParent].child1 == sibling) - { - m_nodes[oldParent].child1 = newParent; - } - else - { - m_nodes[oldParent].child2 = newParent; - } - - m_nodes[newParent].child1 = sibling; - m_nodes[newParent].child2 = leaf; - m_nodes[sibling].parent = newParent; - m_nodes[leaf].parent = newParent; - } - else - { - // The sibling was the root. - m_nodes[newParent].child1 = sibling; - m_nodes[newParent].child2 = leaf; - m_nodes[sibling].parent = newParent; - m_nodes[leaf].parent = newParent; - m_root = newParent; - } - - // Walk back up the tree fixing heights and AABBs - index = m_nodes[leaf].parent; - while (index != b2_nullNode) - { - index = Balance(index); - - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - b2Assert(child1 != b2_nullNode); - b2Assert(child2 != b2_nullNode); - - m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); - m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - - index = m_nodes[index].parent; - } - - //Validate(); -} - -void b2DynamicTree::RemoveLeaf(int32 leaf) -{ - if (leaf == m_root) - { - m_root = b2_nullNode; - return; - } - - int32 parent = m_nodes[leaf].parent; - int32 grandParent = m_nodes[parent].parent; - int32 sibling; - if (m_nodes[parent].child1 == leaf) - { - sibling = m_nodes[parent].child2; - } - else - { - sibling = m_nodes[parent].child1; - } - - if (grandParent != b2_nullNode) - { - // Destroy parent and connect sibling to grandParent. - if (m_nodes[grandParent].child1 == parent) - { - m_nodes[grandParent].child1 = sibling; - } - else - { - m_nodes[grandParent].child2 = sibling; - } - m_nodes[sibling].parent = grandParent; - FreeNode(parent); - - // Adjust ancestor bounds. - int32 index = grandParent; - while (index != b2_nullNode) - { - index = Balance(index); - - int32 child1 = m_nodes[index].child1; - int32 child2 = m_nodes[index].child2; - - m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); - - index = m_nodes[index].parent; - } - } - else - { - m_root = sibling; - m_nodes[sibling].parent = b2_nullNode; - FreeNode(parent); - } - - //Validate(); -} - -// Perform a left or right rotation if node A is imbalanced. -// Returns the new root index. -int32 b2DynamicTree::Balance(int32 iA) -{ - b2Assert(iA != b2_nullNode); - - b2TreeNode* A = m_nodes + iA; - if (A->IsLeaf() || A->height < 2) - { - return iA; - } - - int32 iB = A->child1; - int32 iC = A->child2; - b2Assert(0 <= iB && iB < m_nodeCapacity); - b2Assert(0 <= iC && iC < m_nodeCapacity); - - b2TreeNode* B = m_nodes + iB; - b2TreeNode* C = m_nodes + iC; - - int32 balance = C->height - B->height; - - // Rotate C up - if (balance > 1) - { - int32 iF = C->child1; - int32 iG = C->child2; - b2TreeNode* F = m_nodes + iF; - b2TreeNode* G = m_nodes + iG; - b2Assert(0 <= iF && iF < m_nodeCapacity); - b2Assert(0 <= iG && iG < m_nodeCapacity); - - // Swap A and C - C->child1 = iA; - C->parent = A->parent; - A->parent = iC; - - // A's old parent should point to C - if (C->parent != b2_nullNode) - { - if (m_nodes[C->parent].child1 == iA) - { - m_nodes[C->parent].child1 = iC; - } - else - { - b2Assert(m_nodes[C->parent].child2 == iA); - m_nodes[C->parent].child2 = iC; - } - } - else - { - m_root = iC; - } - - // Rotate - if (F->height > G->height) - { - C->child2 = iF; - A->child2 = iG; - G->parent = iA; - A->aabb.Combine(B->aabb, G->aabb); - C->aabb.Combine(A->aabb, F->aabb); - - A->height = 1 + b2Max(B->height, G->height); - C->height = 1 + b2Max(A->height, F->height); - } - else - { - C->child2 = iG; - A->child2 = iF; - F->parent = iA; - A->aabb.Combine(B->aabb, F->aabb); - C->aabb.Combine(A->aabb, G->aabb); - - A->height = 1 + b2Max(B->height, F->height); - C->height = 1 + b2Max(A->height, G->height); - } - - return iC; - } - - // Rotate B up - if (balance < -1) - { - int32 iD = B->child1; - int32 iE = B->child2; - b2TreeNode* D = m_nodes + iD; - b2TreeNode* E = m_nodes + iE; - b2Assert(0 <= iD && iD < m_nodeCapacity); - b2Assert(0 <= iE && iE < m_nodeCapacity); - - // Swap A and B - B->child1 = iA; - B->parent = A->parent; - A->parent = iB; - - // A's old parent should point to B - if (B->parent != b2_nullNode) - { - if (m_nodes[B->parent].child1 == iA) - { - m_nodes[B->parent].child1 = iB; - } - else - { - b2Assert(m_nodes[B->parent].child2 == iA); - m_nodes[B->parent].child2 = iB; - } - } - else - { - m_root = iB; - } - - // Rotate - if (D->height > E->height) - { - B->child2 = iD; - A->child1 = iE; - E->parent = iA; - A->aabb.Combine(C->aabb, E->aabb); - B->aabb.Combine(A->aabb, D->aabb); - - A->height = 1 + b2Max(C->height, E->height); - B->height = 1 + b2Max(A->height, D->height); - } - else - { - B->child2 = iE; - A->child1 = iD; - D->parent = iA; - A->aabb.Combine(C->aabb, D->aabb); - B->aabb.Combine(A->aabb, E->aabb); - - A->height = 1 + b2Max(C->height, D->height); - B->height = 1 + b2Max(A->height, E->height); - } - - return iB; - } - - return iA; -} - -int32 b2DynamicTree::GetHeight() const -{ - if (m_root == b2_nullNode) - { - return 0; - } - - return m_nodes[m_root].height; -} - -// -float32 b2DynamicTree::GetAreaRatio() const -{ - if (m_root == b2_nullNode) - { - return 0.0f; - } - - const b2TreeNode* root = m_nodes + m_root; - float32 rootArea = root->aabb.GetPerimeter(); - - float32 totalArea = 0.0f; - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - const b2TreeNode* node = m_nodes + i; - if (node->height < 0) - { - // Free node in pool - continue; - } - - totalArea += node->aabb.GetPerimeter(); - } - - return totalArea / rootArea; -} - -// Compute the height of a sub-tree. -int32 b2DynamicTree::ComputeHeight(int32 nodeId) const -{ - b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); - b2TreeNode* node = m_nodes + nodeId; - - if (node->IsLeaf()) - { - return 0; - } - - int32 height1 = ComputeHeight(node->child1); - int32 height2 = ComputeHeight(node->child2); - return 1 + b2Max(height1, height2); -} - -int32 b2DynamicTree::ComputeHeight() const -{ - int32 height = ComputeHeight(m_root); - return height; -} - -void b2DynamicTree::ValidateStructure(int32 index) const -{ - if (index == b2_nullNode) - { - return; - } - - if (index == m_root) - { - b2Assert(m_nodes[index].parent == b2_nullNode); - } - - const b2TreeNode* node = m_nodes + index; - - int32 child1 = node->child1; - int32 child2 = node->child2; - - if (node->IsLeaf()) - { - b2Assert(child1 == b2_nullNode); - b2Assert(child2 == b2_nullNode); - b2Assert(node->height == 0); - return; - } - - b2Assert(0 <= child1 && child1 < m_nodeCapacity); - b2Assert(0 <= child2 && child2 < m_nodeCapacity); - - b2Assert(m_nodes[child1].parent == index); - b2Assert(m_nodes[child2].parent == index); - - ValidateStructure(child1); - ValidateStructure(child2); -} - -void b2DynamicTree::ValidateMetrics(int32 index) const -{ - if (index == b2_nullNode) - { - return; - } - - const b2TreeNode* node = m_nodes + index; - - int32 child1 = node->child1; - int32 child2 = node->child2; - - if (node->IsLeaf()) - { - b2Assert(child1 == b2_nullNode); - b2Assert(child2 == b2_nullNode); - b2Assert(node->height == 0); - return; - } - - b2Assert(0 <= child1 && child1 < m_nodeCapacity); - b2Assert(0 <= child2 && child2 < m_nodeCapacity); - - int32 height1 = m_nodes[child1].height; - int32 height2 = m_nodes[child2].height; - int32 height; - height = 1 + b2Max(height1, height2); - b2Assert(node->height == height); - - b2AABB aabb; - aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); - - b2Assert(aabb.lowerBound == node->aabb.lowerBound); - b2Assert(aabb.upperBound == node->aabb.upperBound); - - ValidateMetrics(child1); - ValidateMetrics(child2); -} - -void b2DynamicTree::Validate() const -{ - ValidateStructure(m_root); - ValidateMetrics(m_root); - - int32 freeCount = 0; - int32 freeIndex = m_freeList; - while (freeIndex != b2_nullNode) - { - b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); - freeIndex = m_nodes[freeIndex].next; - ++freeCount; - } - - b2Assert(GetHeight() == ComputeHeight()); - - b2Assert(m_nodeCount + freeCount == m_nodeCapacity); -} - -int32 b2DynamicTree::GetMaxBalance() const -{ - int32 maxBalance = 0; - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - const b2TreeNode* node = m_nodes + i; - if (node->height <= 1) - { - continue; - } - - b2Assert(node->IsLeaf() == false); - - int32 child1 = node->child1; - int32 child2 = node->child2; - int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); - maxBalance = b2Max(maxBalance, balance); - } - - return maxBalance; -} - -void b2DynamicTree::RebuildBottomUp() -{ - int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); - int32 count = 0; - - // Build array of leaves. Free the rest. - for (int32 i = 0; i < m_nodeCapacity; ++i) - { - if (m_nodes[i].height < 0) - { - // free node in pool - continue; - } - - if (m_nodes[i].IsLeaf()) - { - m_nodes[i].parent = b2_nullNode; - nodes[count] = i; - ++count; - } - else - { - FreeNode(i); - } - } - - while (count > 1) - { - float32 minCost = b2_maxFloat; - int32 iMin = -1, jMin = -1; - for (int32 i = 0; i < count; ++i) - { - b2AABB aabbi = m_nodes[nodes[i]].aabb; - - for (int32 j = i + 1; j < count; ++j) - { - b2AABB aabbj = m_nodes[nodes[j]].aabb; - b2AABB b; - b.Combine(aabbi, aabbj); - float32 cost = b.GetPerimeter(); - if (cost < minCost) - { - iMin = i; - jMin = j; - minCost = cost; - } - } - } - - int32 index1 = nodes[iMin]; - int32 index2 = nodes[jMin]; - b2TreeNode* child1 = m_nodes + index1; - b2TreeNode* child2 = m_nodes + index2; - - int32 parentIndex = AllocateNode(); - b2TreeNode* parent = m_nodes + parentIndex; - parent->child1 = index1; - parent->child2 = index2; - parent->height = 1 + b2Max(child1->height, child2->height); - parent->aabb.Combine(child1->aabb, child2->aabb); - parent->parent = b2_nullNode; - - child1->parent = parentIndex; - child2->parent = parentIndex; - - nodes[jMin] = nodes[count-1]; - nodes[iMin] = parentIndex; - --count; - } - - m_root = nodes[0]; - b2Free(nodes); - - Validate(); -} diff --git a/external/box2d/Collision/b2DynamicTree.h b/external/box2d/Collision/b2DynamicTree.h deleted file mode 100644 index 33f16b0f32..0000000000 --- a/external/box2d/Collision/b2DynamicTree.h +++ /dev/null @@ -1,284 +0,0 @@ -/* -* Copyright (c) 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. -*/ - -#ifndef B2_DYNAMIC_TREE_H -#define B2_DYNAMIC_TREE_H - -#include -#include - -#define b2_nullNode (-1) - -/// A node in the dynamic tree. The client does not interact with this directly. -struct b2TreeNode -{ - bool IsLeaf() const - { - return child1 == b2_nullNode; - } - - /// Enlarged AABB - b2AABB aabb; - - void* userData; - - union - { - int32 parent; - int32 next; - }; - - int32 child1; - int32 child2; - - // leaf = 0, free node = -1 - int32 height; -}; - -/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. -/// A dynamic tree arranges data in a binary tree to accelerate -/// queries such as volume queries and ray casts. Leafs are proxies -/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor -/// so that the proxy AABB is bigger than the client object. This allows the client -/// object to move by small amounts without triggering a tree update. -/// -/// Nodes are pooled and relocatable, so we use node indices rather than pointers. -class b2DynamicTree -{ -public: - /// Constructing the tree initializes the node pool. - b2DynamicTree(); - - /// Destroy the tree, freeing the node pool. - ~b2DynamicTree(); - - /// Create a proxy. Provide a tight fitting AABB and a userData pointer. - int32 CreateProxy(const b2AABB& aabb, void* userData); - - /// Destroy a proxy. This asserts if the id is invalid. - void DestroyProxy(int32 proxyId); - - /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, - /// then the proxy is removed from the tree and re-inserted. Otherwise - /// the function returns immediately. - /// @return true if the proxy was re-inserted. - bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); - - /// Get proxy user data. - /// @return the proxy user data or 0 if the id is invalid. - void* GetUserData(int32 proxyId) const; - - /// Get the fat AABB for a proxy. - const b2AABB& GetFatAABB(int32 proxyId) const; - - /// Query an AABB for overlapping proxies. The callback class - /// is called for each proxy that overlaps the supplied AABB. - template - void Query(T* callback, const b2AABB& aabb) const; - - /// Ray-cast against the proxies in the tree. This relies on the callback - /// to perform a exact ray-cast in the case were the proxy contains a shape. - /// The callback also performs the any collision filtering. This has performance - /// roughly equal to k * log(n), where k is the number of collisions and n is the - /// number of proxies in the tree. - /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). - /// @param callback a callback class that is called for each proxy that is hit by the ray. - template - void RayCast(T* callback, const b2RayCastInput& input) const; - - /// Validate this tree. For testing. - void Validate() const; - - /// Compute the height of the binary tree in O(N) time. Should not be - /// called often. - int32 GetHeight() const; - - /// Get the maximum balance of an node in the tree. The balance is the difference - /// in height of the two children of a node. - int32 GetMaxBalance() const; - - /// Get the ratio of the sum of the node areas to the root area. - float32 GetAreaRatio() const; - - /// Build an optimal tree. Very expensive. For testing. - void RebuildBottomUp(); - -private: - - int32 AllocateNode(); - void FreeNode(int32 node); - - void InsertLeaf(int32 node); - void RemoveLeaf(int32 node); - - int32 Balance(int32 index); - - int32 ComputeHeight() const; - int32 ComputeHeight(int32 nodeId) const; - - void ValidateStructure(int32 index) const; - void ValidateMetrics(int32 index) const; - - int32 m_root; - - b2TreeNode* m_nodes; - int32 m_nodeCount; - int32 m_nodeCapacity; - - int32 m_freeList; - - /// This is used to incrementally traverse the tree for re-balancing. - uint32 m_path; - - int32 m_insertionCount; -}; - -inline void* b2DynamicTree::GetUserData(int32 proxyId) const -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - return m_nodes[proxyId].userData; -} - -inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const -{ - b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); - return m_nodes[proxyId].aabb; -} - -template -inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const -{ - b2GrowableStack stack; - stack.Push(m_root); - - while (stack.GetCount() > 0) - { - int32 nodeId = stack.Pop(); - if (nodeId == b2_nullNode) - { - continue; - } - - const b2TreeNode* node = m_nodes + nodeId; - - if (b2TestOverlap(node->aabb, aabb)) - { - if (node->IsLeaf()) - { - bool proceed = callback->QueryCallback(nodeId); - if (proceed == false) - { - return; - } - } - else - { - stack.Push(node->child1); - stack.Push(node->child2); - } - } - } -} - -template -inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const -{ - b2Vec2 p1 = input.p1; - b2Vec2 p2 = input.p2; - b2Vec2 r = p2 - p1; - b2Assert(r.LengthSquared() > 0.0f); - r.Normalize(); - - // v is perpendicular to the segment. - b2Vec2 v = b2Cross(1.0f, r); - b2Vec2 abs_v = b2Abs(v); - - // Separating axis for segment (Gino, p80). - // |dot(v, p1 - c)| > dot(|v|, h) - - float32 maxFraction = input.maxFraction; - - // Build a bounding box for the segment. - b2AABB segmentAABB; - { - b2Vec2 t = p1 + maxFraction * (p2 - p1); - segmentAABB.lowerBound = b2Min(p1, t); - segmentAABB.upperBound = b2Max(p1, t); - } - - b2GrowableStack stack; - stack.Push(m_root); - - while (stack.GetCount() > 0) - { - int32 nodeId = stack.Pop(); - if (nodeId == b2_nullNode) - { - continue; - } - - const b2TreeNode* node = m_nodes + nodeId; - - if (b2TestOverlap(node->aabb, segmentAABB) == false) - { - continue; - } - - // Separating axis for segment (Gino, p80). - // |dot(v, p1 - c)| > dot(|v|, h) - b2Vec2 c = node->aabb.GetCenter(); - b2Vec2 h = node->aabb.GetExtents(); - float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); - if (separation > 0.0f) - { - continue; - } - - if (node->IsLeaf()) - { - b2RayCastInput subInput; - subInput.p1 = input.p1; - subInput.p2 = input.p2; - subInput.maxFraction = maxFraction; - - float32 value = callback->RayCastCallback(subInput, nodeId); - - if (value == 0.0f) - { - // The client has terminated the ray cast. - return; - } - - if (value > 0.0f) - { - // Update segment bounding box. - maxFraction = value; - b2Vec2 t = p1 + maxFraction * (p2 - p1); - segmentAABB.lowerBound = b2Min(p1, t); - segmentAABB.upperBound = b2Max(p1, t); - } - } - else - { - stack.Push(node->child1); - stack.Push(node->child2); - } - } -} - -#endif diff --git a/external/box2d/Collision/b2TimeOfImpact.cpp b/external/box2d/Collision/b2TimeOfImpact.cpp deleted file mode 100644 index 1d643addd8..0000000000 --- a/external/box2d/Collision/b2TimeOfImpact.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include -#include -#include -#include -#include - -#ifdef SHP -#include -#else -#include -#endif - -using namespace std; - -int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; -int32 b2_toiRootIters, b2_toiMaxRootIters; - -struct b2SeparationFunction -{ - enum Type - { - e_points, - e_faceA, - e_faceB - }; - - // TODO_ERIN might not need to return the separation - - float32 Initialize(const b2SimplexCache* cache, - const b2DistanceProxy* proxyA, const b2Sweep& sweepA, - const b2DistanceProxy* proxyB, const b2Sweep& sweepB, - float32 t1) - { - m_proxyA = proxyA; - m_proxyB = proxyB; - int32 count = cache->count; - b2Assert(0 < count && count < 3); - - m_sweepA = sweepA; - m_sweepB = sweepB; - - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t1); - m_sweepB.GetTransform(&xfB, t1); - - if (count == 1) - { - m_type = e_points; - b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); - b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - m_axis = pointB - pointA; - float32 s = m_axis.Normalize(); - return s; - } - else if (cache->indexA[0] == cache->indexA[1]) - { - // Two points on B and one on A. - m_type = e_faceB; - b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); - b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); - - m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); - m_axis.Normalize(); - b2Vec2 normal = b2Mul(xfB.q, m_axis); - - m_localPoint = 0.5f * (localPointB1 + localPointB2); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 s = b2Dot(pointA - pointB, normal); - if (s < 0.0f) - { - m_axis = -m_axis; - s = -s; - } - return s; - } - else - { - // Two points on A and one or two points on B. - m_type = e_faceA; - b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); - b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); - - m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); - m_axis.Normalize(); - b2Vec2 normal = b2Mul(xfA.q, m_axis); - - m_localPoint = 0.5f * (localPointA1 + localPointA2); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 s = b2Dot(pointB - pointA, normal); - if (s < 0.0f) - { - m_axis = -m_axis; - s = -s; - } - return s; - } - } - - float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const - { - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t); - m_sweepB.GetTransform(&xfB, t); - - switch (m_type) - { - case e_points: - { - b2Vec2 axisA = b2MulT(xfA.q, m_axis); - b2Vec2 axisB = b2MulT(xfB.q, -m_axis); - - *indexA = m_proxyA->GetSupport(axisA); - *indexB = m_proxyB->GetSupport(axisB); - - b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); - b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); - - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, m_axis); - return separation; - } - - case e_faceA: - { - b2Vec2 normal = b2Mul(xfA.q, m_axis); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 axisB = b2MulT(xfB.q, -normal); - - *indexA = -1; - *indexB = m_proxyB->GetSupport(axisB); - - b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, normal); - return separation; - } - - case e_faceB: - { - b2Vec2 normal = b2Mul(xfB.q, m_axis); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 axisA = b2MulT(xfA.q, -normal); - - *indexB = -1; - *indexA = m_proxyA->GetSupport(axisA); - - b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 separation = b2Dot(pointA - pointB, normal); - return separation; - } - - default: - b2Assert(false); - *indexA = -1; - *indexB = -1; - return 0.0f; - } - } - - float32 Evaluate(int32 indexA, int32 indexB, float32 t) const - { - b2Transform xfA, xfB; - m_sweepA.GetTransform(&xfA, t); - m_sweepB.GetTransform(&xfB, t); - - switch (m_type) - { - case e_points: - { - b2Vec2 axisA = b2MulT(xfA.q, m_axis); - b2Vec2 axisB = b2MulT(xfB.q, -m_axis); - - b2Vec2 localPointA = m_proxyA->GetVertex(indexA); - b2Vec2 localPointB = m_proxyB->GetVertex(indexB); - - b2Vec2 pointA = b2Mul(xfA, localPointA); - b2Vec2 pointB = b2Mul(xfB, localPointB); - float32 separation = b2Dot(pointB - pointA, m_axis); - - return separation; - } - - case e_faceA: - { - b2Vec2 normal = b2Mul(xfA.q, m_axis); - b2Vec2 pointA = b2Mul(xfA, m_localPoint); - - b2Vec2 axisB = b2MulT(xfB.q, -normal); - - b2Vec2 localPointB = m_proxyB->GetVertex(indexB); - b2Vec2 pointB = b2Mul(xfB, localPointB); - - float32 separation = b2Dot(pointB - pointA, normal); - return separation; - } - - case e_faceB: - { - b2Vec2 normal = b2Mul(xfB.q, m_axis); - b2Vec2 pointB = b2Mul(xfB, m_localPoint); - - b2Vec2 axisA = b2MulT(xfA.q, -normal); - - b2Vec2 localPointA = m_proxyA->GetVertex(indexA); - b2Vec2 pointA = b2Mul(xfA, localPointA); - - float32 separation = b2Dot(pointA - pointB, normal); - return separation; - } - - default: - b2Assert(false); - return 0.0f; - } - } - - const b2DistanceProxy* m_proxyA; - const b2DistanceProxy* m_proxyB; - b2Sweep m_sweepA, m_sweepB; - Type m_type; - b2Vec2 m_localPoint; - b2Vec2 m_axis; -}; - -// CCD via the local separating axis method. This seeks progression -// by computing the largest time at which separation is maintained. -void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) -{ - ++b2_toiCalls; - - output->state = b2TOIOutput::e_unknown; - output->t = input->tMax; - - const b2DistanceProxy* proxyA = &input->proxyA; - const b2DistanceProxy* proxyB = &input->proxyB; - - b2Sweep sweepA = input->sweepA; - b2Sweep sweepB = input->sweepB; - - // Large rotations can make the root finder fail, so we normalize the - // sweep angles. - sweepA.Normalize(); - sweepB.Normalize(); - - float32 tMax = input->tMax; - - float32 totalRadius = proxyA->m_radius + proxyB->m_radius; - float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); - float32 tolerance = 0.25f * b2_linearSlop; - b2Assert(target > tolerance); - - float32 t1 = 0.0f; - const int32 k_maxIterations = 20; // TODO_ERIN b2Settings - int32 iter = 0; - - // Prepare input for distance query. - b2SimplexCache cache; - cache.count = 0; - b2DistanceInput distanceInput; - distanceInput.proxyA = input->proxyA; - distanceInput.proxyB = input->proxyB; - distanceInput.useRadii = false; - - // The outer loop progressively attempts to compute new separating axes. - // This loop terminates when an axis is repeated (no progress is made). - for(;;) - { - b2Transform xfA, xfB; - sweepA.GetTransform(&xfA, t1); - sweepB.GetTransform(&xfB, t1); - - // Get the distance between shapes. We can also use the results - // to get a separating axis. - distanceInput.transformA = xfA; - distanceInput.transformB = xfB; - b2DistanceOutput distanceOutput; - b2Distance(&distanceOutput, &cache, &distanceInput); - - // If the shapes are overlapped, we give up on continuous collision. - if (distanceOutput.distance <= 0.0f) - { - // Failure! - output->state = b2TOIOutput::e_overlapped; - output->t = 0.0f; - break; - } - - if (distanceOutput.distance < target + tolerance) - { - // Victory! - output->state = b2TOIOutput::e_touching; - output->t = t1; - break; - } - - // Initialize the separating axis. - b2SeparationFunction fcn; - fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); -#if 0 - // Dump the curve seen by the root finder - { - const int32 N = 100; - float32 dx = 1.0f / N; - float32 xs[N+1]; - float32 fs[N+1]; - - float32 x = 0.0f; - - for (int32 i = 0; i <= N; ++i) - { - sweepA.GetTransform(&xfA, x); - sweepB.GetTransform(&xfB, x); - float32 f = fcn.Evaluate(xfA, xfB) - target; - - printf("%g %g\n", x, f); - - xs[i] = x; - fs[i] = f; - - x += dx; - } - } -#endif - - // Compute the TOI on the separating axis. We do this by successively - // resolving the deepest point. This loop is bounded by the number of vertices. - bool done = false; - float32 t2 = tMax; - int32 pushBackIter = 0; - for (;;) - { - // Find the deepest point at t2. Store the witness point indices. - int32 indexA, indexB; - float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); - - // Is the final configuration separated? - if (s2 > target + tolerance) - { - // Victory! - output->state = b2TOIOutput::e_separated; - output->t = tMax; - done = true; - break; - } - - // Has the separation reached tolerance? - if (s2 > target - tolerance) - { - // Advance the sweeps - t1 = t2; - break; - } - - // Compute the initial separation of the witness points. - float32 s1 = fcn.Evaluate(indexA, indexB, t1); - - // Check for initial overlap. This might happen if the root finder - // runs out of iterations. - if (s1 < target - tolerance) - { - output->state = b2TOIOutput::e_failed; - output->t = t1; - done = true; - break; - } - - // Check for touching - if (s1 <= target + tolerance) - { - // Victory! t1 should hold the TOI (could be 0.0). - output->state = b2TOIOutput::e_touching; - output->t = t1; - done = true; - break; - } - - // Compute 1D root of: f(x) - target = 0 - int32 rootIterCount = 0; - float32 a1 = t1, a2 = t2; - for (;;) - { - // Use a mix of the secant rule and bisection. - float32 t; - if (rootIterCount & 1) - { - // Secant rule to improve convergence. - t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); - } - else - { - // Bisection to guarantee progress. - t = 0.5f * (a1 + a2); - } - - float32 s = fcn.Evaluate(indexA, indexB, t); - - if (b2Abs(s - target) < tolerance) - { - // t2 holds a tentative value for t1 - t2 = t; - break; - } - - // Ensure we continue to bracket the root. - if (s > target) - { - a1 = t; - s1 = s; - } - else - { - a2 = t; - s2 = s; - } - - ++rootIterCount; - ++b2_toiRootIters; - - if (rootIterCount == 50) - { - break; - } - } - - b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); - - ++pushBackIter; - - if (pushBackIter == b2_maxPolygonVertices) - { - break; - } - } - - ++iter; - ++b2_toiIters; - - if (done) - { - break; - } - - if (iter == k_maxIterations) - { - // Root finder got stuck. Semi-victory. - output->state = b2TOIOutput::e_failed; - output->t = t1; - break; - } - } - - b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); -} diff --git a/external/box2d/Collision/b2TimeOfImpact.h b/external/box2d/Collision/b2TimeOfImpact.h deleted file mode 100644 index 2e4f8228ff..0000000000 --- a/external/box2d/Collision/b2TimeOfImpact.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_TIME_OF_IMPACT_H -#define B2_TIME_OF_IMPACT_H - -#include -#include - -/// Input parameters for b2TimeOfImpact -struct b2TOIInput -{ - b2DistanceProxy proxyA; - b2DistanceProxy proxyB; - b2Sweep sweepA; - b2Sweep sweepB; - float32 tMax; // defines sweep interval [0, tMax] -}; - -// Output parameters for b2TimeOfImpact. -struct b2TOIOutput -{ - enum State - { - e_unknown, - e_failed, - e_overlapped, - e_touching, - e_separated - }; - - State state; - float32 t; -}; - -/// Compute the upper bound on time before two shapes penetrate. Time is represented as -/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, -/// non-tunneling collision. If you change the time interval, you should call this function -/// again. -/// Note: use b2Distance to compute the contact point and normal at the time of impact. -void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); - -#endif diff --git a/external/box2d/Common/b2BlockAllocator.cpp b/external/box2d/Common/b2BlockAllocator.cpp deleted file mode 100644 index 2e862091f9..0000000000 --- a/external/box2d/Common/b2BlockAllocator.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include - -using namespace std; - -int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = -{ - 16, // 0 - 32, // 1 - 64, // 2 - 96, // 3 - 128, // 4 - 160, // 5 - 192, // 6 - 224, // 7 - 256, // 8 - 320, // 9 - 384, // 10 - 448, // 11 - 512, // 12 - 640, // 13 -}; -uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; -bool b2BlockAllocator::s_blockSizeLookupInitialized; - -struct b2Chunk -{ - int32 blockSize; - b2Block* blocks; -}; - -struct b2Block -{ - b2Block* next; -}; - -b2BlockAllocator::b2BlockAllocator() -{ - b2Assert(b2_blockSizes < UCHAR_MAX); - - m_chunkSpace = b2_chunkArrayIncrement; - m_chunkCount = 0; - m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); - - memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); - memset(m_freeLists, 0, sizeof(m_freeLists)); - - if (s_blockSizeLookupInitialized == false) - { - int32 j = 0; - for (int32 i = 1; i <= b2_maxBlockSize; ++i) - { - b2Assert(j < b2_blockSizes); - if (i <= s_blockSizes[j]) - { - s_blockSizeLookup[i] = (uint8)j; - } - else - { - ++j; - s_blockSizeLookup[i] = (uint8)j; - } - } - - s_blockSizeLookupInitialized = true; - } -} - -b2BlockAllocator::~b2BlockAllocator() -{ - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Free(m_chunks[i].blocks); - } - - b2Free(m_chunks); -} - -void* b2BlockAllocator::Allocate(int32 size) -{ - if (size == 0) - return NULL; - - b2Assert(0 < size); - - if (size > b2_maxBlockSize) - { - return b2Alloc(size); - } - - int32 index = s_blockSizeLookup[size]; - b2Assert(0 <= index && index < b2_blockSizes); - - if (m_freeLists[index]) - { - b2Block* block = m_freeLists[index]; - m_freeLists[index] = block->next; - return block; - } - else - { - if (m_chunkCount == m_chunkSpace) - { - b2Chunk* oldChunks = m_chunks; - m_chunkSpace += b2_chunkArrayIncrement; - m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); - memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); - memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); - b2Free(oldChunks); - } - - b2Chunk* chunk = m_chunks + m_chunkCount; - chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); -#if defined(_DEBUG) - memset(chunk->blocks, 0xcd, b2_chunkSize); -#endif - int32 blockSize = s_blockSizes[index]; - chunk->blockSize = blockSize; - int32 blockCount = b2_chunkSize / blockSize; - b2Assert(blockCount * blockSize <= b2_chunkSize); - for (int32 i = 0; i < blockCount - 1; ++i) - { - b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); - b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); - block->next = next; - } - b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); - last->next = NULL; - - m_freeLists[index] = chunk->blocks->next; - ++m_chunkCount; - - return chunk->blocks; - } -} - -void b2BlockAllocator::Free(void* p, int32 size) -{ - if (size == 0) - { - return; - } - - b2Assert(0 < size); - - if (size > b2_maxBlockSize) - { - b2Free(p); - return; - } - - int32 index = s_blockSizeLookup[size]; - b2Assert(0 <= index && index < b2_blockSizes); - -#ifdef _DEBUG - // Verify the memory address and size is valid. - int32 blockSize = s_blockSizes[index]; - bool found = false; - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Chunk* chunk = m_chunks + i; - if (chunk->blockSize != blockSize) - { - b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || - (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); - } - else - { - if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) - { - found = true; - } - } - } - - b2Assert(found); - - memset(p, 0xfd, blockSize); -#endif - - b2Block* block = (b2Block*)p; - block->next = m_freeLists[index]; - m_freeLists[index] = block; -} - -void b2BlockAllocator::Clear() -{ - for (int32 i = 0; i < m_chunkCount; ++i) - { - b2Free(m_chunks[i].blocks); - } - - m_chunkCount = 0; - memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); - - memset(m_freeLists, 0, sizeof(m_freeLists)); -} diff --git a/external/box2d/Common/b2BlockAllocator.h b/external/box2d/Common/b2BlockAllocator.h deleted file mode 100644 index ec221fdf61..0000000000 --- a/external/box2d/Common/b2BlockAllocator.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_BLOCK_ALLOCATOR_H -#define B2_BLOCK_ALLOCATOR_H - -#include - -const int32 b2_chunkSize = 16 * 1024; -const int32 b2_maxBlockSize = 640; -const int32 b2_blockSizes = 14; -const int32 b2_chunkArrayIncrement = 128; - -struct b2Block; -struct b2Chunk; - -/// This is a small object allocator used for allocating small -/// objects that persist for more than one time step. -/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp -class b2BlockAllocator -{ -public: - b2BlockAllocator(); - ~b2BlockAllocator(); - - /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. - void* Allocate(int32 size); - - /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. - void Free(void* p, int32 size); - - void Clear(); - -private: - - b2Chunk* m_chunks; - int32 m_chunkCount; - int32 m_chunkSpace; - - b2Block* m_freeLists[b2_blockSizes]; - - static int32 s_blockSizes[b2_blockSizes]; - static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; - static bool s_blockSizeLookupInitialized; -}; - -#endif diff --git a/external/box2d/Common/b2Draw.cpp b/external/box2d/Common/b2Draw.cpp deleted file mode 100644 index cb760025e9..0000000000 --- a/external/box2d/Common/b2Draw.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -b2Draw::b2Draw() -{ - m_drawFlags = 0; -} - -void b2Draw::SetFlags(uint32 flags) -{ - m_drawFlags = flags; -} - -uint32 b2Draw::GetFlags() const -{ - return m_drawFlags; -} - -void b2Draw::AppendFlags(uint32 flags) -{ - m_drawFlags |= flags; -} - -void b2Draw::ClearFlags(uint32 flags) -{ - m_drawFlags &= ~flags; -} diff --git a/external/box2d/Common/b2Draw.h b/external/box2d/Common/b2Draw.h deleted file mode 100644 index b33cd8d38f..0000000000 --- a/external/box2d/Common/b2Draw.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -/// Color for debug drawing. Each value has the range [0,1]. -struct b2Color -{ - b2Color() {} - b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} - void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } - float32 r, g, b; -}; - -/// Implement and register this class with a b2World to provide debug drawing of physics -/// entities in your game. -class b2Draw -{ -public: - b2Draw(); - - virtual ~b2Draw() {} - - enum - { - e_shapeBit = 0x0001, ///< draw shapes - e_jointBit = 0x0002, ///< draw joint connections - e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes - e_pairBit = 0x0008, ///< draw broad-phase pairs - e_centerOfMassBit = 0x0010 ///< draw center of mass frame - }; - - /// Set the drawing flags. - void SetFlags(uint32 flags); - - /// Get the drawing flags. - uint32 GetFlags() const; - - /// Append flags to the current flags. - void AppendFlags(uint32 flags); - - /// Clear flags from the current flags. - void ClearFlags(uint32 flags); - - /// Draw a closed polygon provided in CCW order. - virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; - - /// Draw a solid closed polygon provided in CCW order. - virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; - - /// Draw a circle. - virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; - - /// Draw a solid circle. - virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; - - /// Draw a line segment. - virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; - - /// Draw a transform. Choose your own length scale. - /// @param xf a transform. - virtual void DrawTransform(const b2Transform& xf) = 0; - -protected: - uint32 m_drawFlags; -}; diff --git a/external/box2d/Common/b2GrowableStack.h b/external/box2d/Common/b2GrowableStack.h deleted file mode 100644 index 68809521f4..0000000000 --- a/external/box2d/Common/b2GrowableStack.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -* Copyright (c) 2010 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. -*/ - -#ifndef B2_GROWABLE_STACK_H -#define B2_GROWABLE_STACK_H -#include -#include - -/// This is a growable LIFO stack with an initial capacity of N. -/// If the stack size exceeds the initial capacity, the heap is used -/// to increase the size of the stack. -template -class b2GrowableStack -{ -public: - b2GrowableStack() - { - m_stack = m_array; - m_count = 0; - m_capacity = N; - } - - ~b2GrowableStack() - { - if (m_stack != m_array) - { - b2Free(m_stack); - m_stack = NULL; - } - } - - void Push(const T& element) - { - if (m_count == m_capacity) - { - T* old = m_stack; - m_capacity *= 2; - m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); - std::memcpy(m_stack, old, m_count * sizeof(T)); - if (old != m_array) - { - b2Free(old); - } - } - - m_stack[m_count] = element; - ++m_count; - } - - T Pop() - { - b2Assert(m_count > 0); - --m_count; - return m_stack[m_count]; - } - - int32 GetCount() - { - return m_count; - } - -private: - T* m_stack; - T m_array[N]; - int32 m_count; - int32 m_capacity; -}; - - -#endif diff --git a/external/box2d/Common/b2Math.cpp b/external/box2d/Common/b2Math.cpp deleted file mode 100644 index 15d68fce96..0000000000 --- a/external/box2d/Common/b2Math.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org -* -* This software is provided 'as-is', without any express or implied -* warranty. In no event will the authors be held liable for any damages -* arising from the use of this software. -* Permission is granted to anyone to use this software for any purpose, -* including commercial applications, and to alter it and redistribute it -* freely, subject to the following restrictions: -* 1. The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software -* in a product, an acknowledgment in the product documentation would be -* appreciated but is not required. -* 2. Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* 3. This notice may not be removed or altered from any source distribution. -*/ - -#include - -const b2Vec2 b2Vec2_zero(0.0f, 0.0f); - -/// Solve A * x = b, where b is a column vector. This is more efficient -/// than computing the inverse in one-shot cases. -b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const -{ - float32 det = b2Dot(ex, b2Cross(ey, ez)); - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec3 x; - x.x = det * b2Dot(b, b2Cross(ey, ez)); - x.y = det * b2Dot(ex, b2Cross(b, ez)); - x.z = det * b2Dot(ex, b2Cross(ey, b)); - return x; -} - -/// Solve A * x = b, where b is a column vector. This is more efficient -/// than computing the inverse in one-shot cases. -b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const -{ - float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; - float32 det = a11 * a22 - a12 * a21; - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec2 x; - x.x = det * (a22 * b.x - a12 * b.y); - x.y = det * (a11 * b.y - a21 * b.x); - return x; -} - -/// -void b2Mat33::GetInverse22(b2Mat33* M) const -{ - float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; - float32 det = a * d - b * c; - if (det != 0.0f) - { - det = 1.0f / det; - } - - M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; - M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; - M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; -} - -/// Returns the zero matrix if singular. -void b2Mat33::GetSymInverse33(b2Mat33* M) const -{ - float32 det = b2Dot(ex, b2Cross(ey, ez)); - if (det != 0.0f) - { - det = 1.0f / det; - } - - float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; - float32 a22 = ey.y, a23 = ez.y; - float32 a33 = ez.z; - - M->ex.x = det * (a22 * a33 - a23 * a23); - M->ex.y = det * (a13 * a23 - a12 * a33); - M->ex.z = det * (a12 * a23 - a13 * a22); - - M->ey.x = M->ex.y; - M->ey.y = det * (a11 * a33 - a13 * a13); - M->ey.z = det * (a13 * a12 - a11 * a23); - - M->ez.x = M->ex.z; - M->ez.y = M->ey.z; - M->ez.z = det * (a11 * a22 - a12 * a12); -} diff --git a/external/box2d/Common/b2Math.h b/external/box2d/Common/b2Math.h deleted file mode 100644 index a6be671139..0000000000 --- a/external/box2d/Common/b2Math.h +++ /dev/null @@ -1,738 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_MATH_H -#define B2_MATH_H - -#include - -#include -#ifndef SHP -#include -#else -#include -#endif -#include -#include - -using namespace std; - - -/// This function is used to ensure that a floating point number is -/// not a NaN or infinity. -inline bool b2IsValid(float32 x) -{ - if (x != x) - { - // NaN. - return false; - } - - float32 infinity = std::numeric_limits::infinity(); - return -infinity < x && x < infinity; -} - -/// This is a approximate yet fast inverse square-root. -inline float32 b2InvSqrt(float32 x) -{ - union - { - float32 x; - int32 i; - } convert; - - convert.x = x; - float32 xhalf = 0.5f * x; - convert.i = 0x5f3759df - (convert.i >> 1); - x = convert.x; - x = x * (1.5f - xhalf * x * x); - return x; -} - -#define b2Sqrt(x) std::sqrt(x) -#define b2Atan2(y, x) std::atan2(y, x) - -/// A 2D column vector. -struct b2Vec2 -{ - /// Default constructor does nothing (for performance). - b2Vec2() {} - - /// Construct using coordinates. - b2Vec2(float32 x, float32 y) : x(x), y(y) {} - - /// Set this vector to all zeros. - void SetZero() { x = 0.0f; y = 0.0f; } - - /// Set this vector to some specified coordinates. - void Set(float32 x_, float32 y_) { x = x_; y = y_; } - - /// Negate this vector. - b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } - - /// Read from and indexed element. - float32 operator () (int32 i) const - { - return (&x)[i]; - } - - /// Write to an indexed element. - float32& operator () (int32 i) - { - return (&x)[i]; - } - - /// Add a vector to this vector. - void operator += (const b2Vec2& v) - { - x += v.x; y += v.y; - } - - /// Subtract a vector from this vector. - void operator -= (const b2Vec2& v) - { - x -= v.x; y -= v.y; - } - - /// Multiply this vector by a scalar. - void operator *= (float32 a) - { - x *= a; y *= a; - } - - /// Get the length of this vector (the norm). - float32 Length() const - { - return b2Sqrt(x * x + y * y); - } - - /// Get the length squared. For performance, use this instead of - /// b2Vec2::Length (if possible). - float32 LengthSquared() const - { - return x * x + y * y; - } - - /// Convert this vector into a unit vector. Returns the length. - float32 Normalize() - { - float32 length = Length(); - if (length < b2_epsilon) - { - return 0.0f; - } - float32 invLength = 1.0f / length; - x *= invLength; - y *= invLength; - - return length; - } - - /// Does this vector contain finite coordinates? - bool IsValid() const - { - return b2IsValid(x) && b2IsValid(y); - } - - /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) - b2Vec2 Skew() const - { - return b2Vec2(-y, x); - } - - float32 x, y; -}; - -/// A 2D column vector with 3 elements. -struct b2Vec3 -{ - /// Default constructor does nothing (for performance). - b2Vec3() {} - - /// Construct using coordinates. - b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} - - /// Set this vector to all zeros. - void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } - - /// Set this vector to some specified coordinates. - void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } - - /// Negate this vector. - b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } - - /// Add a vector to this vector. - void operator += (const b2Vec3& v) - { - x += v.x; y += v.y; z += v.z; - } - - /// Subtract a vector from this vector. - void operator -= (const b2Vec3& v) - { - x -= v.x; y -= v.y; z -= v.z; - } - - /// Multiply this vector by a scalar. - void operator *= (float32 s) - { - x *= s; y *= s; z *= s; - } - - float32 x, y, z; -}; - -/// A 2-by-2 matrix. Stored in column-major order. -struct b2Mat22 -{ - /// The default constructor does nothing (for performance). - b2Mat22() {} - - /// Construct this matrix using columns. - b2Mat22(const b2Vec2& c1, const b2Vec2& c2) - { - ex = c1; - ey = c2; - } - - /// Construct this matrix using scalars. - b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) - { - ex.x = a11; ex.y = a21; - ey.x = a12; ey.y = a22; - } - - /// Initialize this matrix using columns. - void Set(const b2Vec2& c1, const b2Vec2& c2) - { - ex = c1; - ey = c2; - } - - /// Set this to the identity matrix. - void SetIdentity() - { - ex.x = 1.0f; ey.x = 0.0f; - ex.y = 0.0f; ey.y = 1.0f; - } - - /// Set this matrix to all zeros. - void SetZero() - { - ex.x = 0.0f; ey.x = 0.0f; - ex.y = 0.0f; ey.y = 0.0f; - } - - b2Mat22 GetInverse() const - { - float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; - b2Mat22 B; - float32 det = a * d - b * c; - if (det != 0.0f) - { - det = 1.0f / det; - } - B.ex.x = det * d; B.ey.x = -det * b; - B.ex.y = -det * c; B.ey.y = det * a; - return B; - } - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. - b2Vec2 Solve(const b2Vec2& b) const - { - float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; - float32 det = a11 * a22 - a12 * a21; - if (det != 0.0f) - { - det = 1.0f / det; - } - b2Vec2 x; - x.x = det * (a22 * b.x - a12 * b.y); - x.y = det * (a11 * b.y - a21 * b.x); - return x; - } - - b2Vec2 ex, ey; -}; - -/// A 3-by-3 matrix. Stored in column-major order. -struct b2Mat33 -{ - /// The default constructor does nothing (for performance). - b2Mat33() {} - - /// Construct this matrix using columns. - b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) - { - ex = c1; - ey = c2; - ez = c3; - } - - /// Set this matrix to all zeros. - void SetZero() - { - ex.SetZero(); - ey.SetZero(); - ez.SetZero(); - } - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. - b2Vec3 Solve33(const b2Vec3& b) const; - - /// Solve A * x = b, where b is a column vector. This is more efficient - /// than computing the inverse in one-shot cases. Solve only the upper - /// 2-by-2 matrix equation. - b2Vec2 Solve22(const b2Vec2& b) const; - - /// Get the inverse of this matrix as a 2-by-2. - /// Returns the zero matrix if singular. - void GetInverse22(b2Mat33* M) const; - - /// Get the symmetric inverse of this matrix as a 3-by-3. - /// Returns the zero matrix if singular. - void GetSymInverse33(b2Mat33* M) const; - - b2Vec3 ex, ey, ez; -}; - -/// Rotation -struct b2Rot -{ - b2Rot() {} - - /// Initialize from an angle in radians - explicit b2Rot(float32 angle) - { - /// TODO_ERIN optimize - s = sinf(angle); - c = cosf(angle); - } - - /// Set using an angle in radians. - void Set(float32 angle) - { - /// TODO_ERIN optimize - s = sinf(angle); - c = cosf(angle); - } - - /// Set to the identity rotation - void SetIdentity() - { - s = 0.0f; - c = 1.0f; - } - - /// Get the angle in radians - float32 GetAngle() const - { - return b2Atan2(s, c); - } - - /// Get the x-axis - b2Vec2 GetXAxis() const - { - return b2Vec2(c, s); - } - - /// Get the u-axis - b2Vec2 GetYAxis() const - { - return b2Vec2(-s, c); - } - - /// Sine and cosine - float32 s, c; -}; - -/// A transform contains translation and rotation. It is used to represent -/// the position and orientation of rigid frames. -struct b2Transform -{ - /// The default constructor does nothing. - b2Transform() {} - - /// Initialize using a position vector and a rotation. - b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} - - /// Set this to the identity transform. - void SetIdentity() - { - p.SetZero(); - q.SetIdentity(); - } - - /// Set this based on the position and angle. - void Set(const b2Vec2& position, float32 angle) - { - p = position; - q.Set(angle); - } - - b2Vec2 p; - b2Rot q; -}; - -/// This describes the motion of a body/shape for TOI computation. -/// Shapes are defined with respect to the body origin, which may -/// no coincide with the center of mass. However, to support dynamics -/// we must interpolate the center of mass position. -struct b2Sweep -{ - /// Get the interpolated transform at a specific time. - /// @param beta is a factor in [0,1], where 0 indicates alpha0. - void GetTransform(b2Transform* xfb, float32 beta) const; - - /// Advance the sweep forward, yielding a new initial state. - /// @param alpha the new initial time. - void Advance(float32 alpha); - - /// Normalize the angles. - void Normalize(); - - b2Vec2 localCenter; ///< local center of mass position - b2Vec2 c0, c; ///< center world positions - float32 a0, a; ///< world angles - - /// Fraction of the current time step in the range [0,1] - /// c0 and a0 are the positions at alpha0. - float32 alpha0; -}; - -/// Useful constant -extern const b2Vec2 b2Vec2_zero; - -/// Perform the dot product on two vectors. -inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) -{ - return a.x * b.x + a.y * b.y; -} - -/// Perform the cross product on two vectors. In 2D this produces a scalar. -inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) -{ - return a.x * b.y - a.y * b.x; -} - -/// Perform the cross product on a vector and a scalar. In 2D this produces -/// a vector. -inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) -{ - return b2Vec2(s * a.y, -s * a.x); -} - -/// Perform the cross product on a scalar and a vector. In 2D this produces -/// a vector. -inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) -{ - return b2Vec2(-s * a.y, s * a.x); -} - -/// Multiply a matrix times a vector. If a rotation matrix is provided, -/// then this transforms the vector from one frame to another. -inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) -{ - return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); -} - -/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, -/// then this transforms the vector from one frame to another (inverse transform). -inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) -{ - return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); -} - -/// Add two vectors component-wise. -inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(a.x + b.x, a.y + b.y); -} - -/// Subtract two vectors component-wise. -inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(a.x - b.x, a.y - b.y); -} - -inline b2Vec2 operator * (float32 s, const b2Vec2& a) -{ - return b2Vec2(s * a.x, s * a.y); -} - -inline bool operator == (const b2Vec2& a, const b2Vec2& b) -{ - return a.x == b.x && a.y == b.y; -} - -inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) -{ - b2Vec2 c = a - b; - return c.Length(); -} - -inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) -{ - b2Vec2 c = a - b; - return b2Dot(c, c); -} - -inline b2Vec3 operator * (float32 s, const b2Vec3& a) -{ - return b2Vec3(s * a.x, s * a.y, s * a.z); -} - -/// Add two vectors component-wise. -inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); -} - -/// Subtract two vectors component-wise. -inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); -} - -/// Perform the dot product on two vectors. -inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) -{ - return a.x * b.x + a.y * b.y + a.z * b.z; -} - -/// Perform the cross product on two vectors. -inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) -{ - return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); -} - -inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) -{ - return b2Mat22(A.ex + B.ex, A.ey + B.ey); -} - -// A * B -inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) -{ - return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); -} - -// A^T * B -inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) -{ - b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); - b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); - return b2Mat22(c1, c2); -} - -/// Multiply a matrix times a vector. -inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) -{ - return v.x * A.ex + v.y * A.ey + v.z * A.ez; -} - -/// Multiply a matrix times a vector. -inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) -{ - return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); -} - -/// Multiply two rotations: q * r -inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) -{ - // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] - // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] - // s = qs * rc + qc * rs - // c = qc * rc - qs * rs - b2Rot qr; - qr.s = q.s * r.c + q.c * r.s; - qr.c = q.c * r.c - q.s * r.s; - return qr; -} - -/// Transpose multiply two rotations: qT * r -inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) -{ - // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] - // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] - // s = qc * rs - qs * rc - // c = qc * rc + qs * rs - b2Rot qr; - qr.s = q.c * r.s - q.s * r.c; - qr.c = q.c * r.c + q.s * r.s; - return qr; -} - -/// Rotate a vector -inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) -{ - return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); -} - -/// Inverse rotate a vector -inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) -{ - return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); -} - -inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) -{ - float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; - float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; - - return b2Vec2(x, y); -} - -inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) -{ - float32 px = v.x - T.p.x; - float32 py = v.y - T.p.y; - float32 x = (T.q.c * px + T.q.s * py); - float32 y = (-T.q.s * px + T.q.c * py); - - return b2Vec2(x, y); -} - -// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p -// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p -inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) -{ - b2Transform C; - C.q = b2Mul(A.q, B.q); - C.p = b2Mul(A.q, B.p) + A.p; - return C; -} - -// v2 = A.q' * (B.q * v1 + B.p - A.p) -// = A.q' * B.q * v1 + A.q' * (B.p - A.p) -inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) -{ - b2Transform C; - C.q = b2MulT(A.q, B.q); - C.p = b2MulT(A.q, B.p - A.p); - return C; -} - -template -inline T b2Abs(T a) -{ - return a > T(0) ? a : -a; -} - -inline b2Vec2 b2Abs(const b2Vec2& a) -{ - return b2Vec2(b2Abs(a.x), b2Abs(a.y)); -} - -inline b2Mat22 b2Abs(const b2Mat22& A) -{ - return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); -} - -template -inline T b2Min(T a, T b) -{ - return a < b ? a : b; -} - -inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); -} - -template -inline T b2Max(T a, T b) -{ - return a > b ? a : b; -} - -inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) -{ - return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); -} - -template -inline T b2Clamp(T a, T low, T high) -{ - return b2Max(low, b2Min(a, high)); -} - -inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) -{ - return b2Max(low, b2Min(a, high)); -} - -template inline void b2Swap(T& a, T& b) -{ - T tmp = a; - a = b; - b = tmp; -} - -/// "Next Largest Power of 2 -/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm -/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with -/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next -/// largest power of 2. For a 32-bit value:" -inline uint32 b2NextPowerOfTwo(uint32 x) -{ - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return x + 1; -} - -inline bool b2IsPowerOfTwo(uint32 x) -{ - bool result = x > 0 && (x & (x - 1)) == 0; - return result; -} - -inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const -{ - xf->p = (1.0f - beta) * c0 + beta * c; - float32 angle = (1.0f - beta) * a0 + beta * a; - xf->q.Set(angle); - - // Shift to origin - xf->p -= b2Mul(xf->q, localCenter); -} - -inline void b2Sweep::Advance(float32 alpha) -{ - b2Assert(alpha0 < 1.0f); - float32 beta = (alpha - alpha0) / (1.0f - alpha0); - c0 = (1.0f - beta) * c0 + beta * c; - a0 = (1.0f - beta) * a0 + beta * a; - alpha0 = alpha; -} - -/// Normalize an angle in radians to be between -pi and pi -inline void b2Sweep::Normalize() -{ - float32 twoPi = 2.0f * b2_pi; - float32 d = twoPi * floorf(a0 / twoPi); - a0 -= d; - a -= d; -} - -#endif diff --git a/external/box2d/Common/b2Settings.cpp b/external/box2d/Common/b2Settings.cpp deleted file mode 100644 index 84d6f1d0e4..0000000000 --- a/external/box2d/Common/b2Settings.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Copyright (c) 2006-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 -#ifdef SHP -#include -#include -#include -#include -#else -#include -#include -#include -#endif - - -using namespace std; - - -b2Version b2_version = {2, 2, 1}; - -// Memory allocators. Modify these to use your own allocator. -void* b2Alloc(int32 size) -{ - return malloc(size); -} - -void b2Free(void* mem) -{ - free(mem); -} - -// You can modify this to use your logging facility. -void b2Log(const char* string, ...) -{ -#if defined(SHP) - #ifdef _DEBUG - __App_info(__PRETTY_FUNCTION__ , __LINE__, string); - #endif -#else - va_list args; - va_start(args, string); - vprintf(string, args); - va_end(args); -#endif -} diff --git a/external/box2d/Common/b2Settings.h b/external/box2d/Common/b2Settings.h deleted file mode 100644 index aaf4b12ccf..0000000000 --- a/external/box2d/Common/b2Settings.h +++ /dev/null @@ -1,150 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_SETTINGS_H -#define B2_SETTINGS_H - -#include -#include - -#define B2_NOT_USED(x) ((void)(x)) -#define b2Assert(A) assert(A) - -typedef signed char int8; -typedef signed short int16; -typedef signed int int32; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef float float32; -typedef double float64; - -#define b2_maxFloat FLT_MAX -#define b2_epsilon FLT_EPSILON -#define b2_pi 3.14159265359f - -/// @file -/// Global tuning constants based on meters-kilograms-seconds (MKS) units. -/// - -// Collision - -/// The maximum number of contact points between two convex shapes. Do -/// not change this value. -#define b2_maxManifoldPoints 2 - -/// The maximum number of vertices on a convex polygon. You cannot increase -/// this too much because b2BlockAllocator has a maximum object size. -#define b2_maxPolygonVertices 8 - -/// This is used to fatten AABBs in the dynamic tree. This allows proxies -/// to move by a small amount without triggering a tree adjustment. -/// This is in meters. -#define b2_aabbExtension 0.1f - -/// This is used to fatten AABBs in the dynamic tree. This is used to predict -/// the future position based on the current displacement. -/// This is a dimensionless multiplier. -#define b2_aabbMultiplier 2.0f - -/// A small length used as a collision and constraint tolerance. Usually it is -/// chosen to be numerically significant, but visually insignificant. -#define b2_linearSlop 0.005f - -/// A small angle used as a collision and constraint tolerance. Usually it is -/// chosen to be numerically significant, but visually insignificant. -#define b2_angularSlop (2.0f / 180.0f * b2_pi) - -/// The radius of the polygon/edge shape skin. This should not be modified. Making -/// this smaller means polygons will have an insufficient buffer for continuous collision. -/// Making it larger may create artifacts for vertex collision. -#define b2_polygonRadius (2.0f * b2_linearSlop) - -/// Maximum number of sub-steps per contact in continuous physics simulation. -#define b2_maxSubSteps 8 - - -// Dynamics - -/// Maximum number of contacts to be handled to solve a TOI impact. -#define b2_maxTOIContacts 32 - -/// A velocity threshold for elastic collisions. Any collision with a relative linear -/// velocity below this threshold will be treated as inelastic. -#define b2_velocityThreshold 1.0f - -/// The maximum linear position correction used when solving constraints. This helps to -/// prevent overshoot. -#define b2_maxLinearCorrection 0.2f - -/// The maximum angular position correction used when solving constraints. This helps to -/// prevent overshoot. -#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) - -/// The maximum linear velocity of a body. This limit is very large and is used -/// to prevent numerical problems. You shouldn't need to adjust this. -#define b2_maxTranslation 2.0f -#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) - -/// The maximum angular velocity of a body. This limit is very large and is used -/// to prevent numerical problems. You shouldn't need to adjust this. -#define b2_maxRotation (0.5f * b2_pi) -#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) - -/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so -/// that overlap is removed in one time step. However using values close to 1 often lead -/// to overshoot. -#define b2_baumgarte 0.2f -#define b2_toiBaugarte 0.75f - - -// Sleep - -/// The time that a body must be still before it will go to sleep. -#define b2_timeToSleep 0.5f - -/// A body cannot sleep if its linear velocity is above this tolerance. -#define b2_linearSleepTolerance 0.01f - -/// A body cannot sleep if its angular velocity is above this tolerance. -#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) - -// Memory Allocation - -/// Implement this function to use your own memory allocator. -void* b2Alloc(int32 size); - -/// If you implement b2Alloc, you should also implement this function. -void b2Free(void* mem); - -/// Logging function. -void b2Log(const char* string, ...); - -/// Version numbering scheme. -/// See http://en.wikipedia.org/wiki/Software_versioning -struct b2Version -{ - int32 major; ///< significant changes - int32 minor; ///< incremental changes - int32 revision; ///< bug fixes -}; - -/// Current version. -extern b2Version b2_version; - -#endif diff --git a/external/box2d/Common/b2StackAllocator.cpp b/external/box2d/Common/b2StackAllocator.cpp deleted file mode 100644 index 3caa5d9127..0000000000 --- a/external/box2d/Common/b2StackAllocator.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -b2StackAllocator::b2StackAllocator() -{ - m_index = 0; - m_allocation = 0; - m_maxAllocation = 0; - m_entryCount = 0; -} - -b2StackAllocator::~b2StackAllocator() -{ - b2Assert(m_index == 0); - b2Assert(m_entryCount == 0); -} - -void* b2StackAllocator::Allocate(int32 size) -{ - b2Assert(m_entryCount < b2_maxStackEntries); - - b2StackEntry* entry = m_entries + m_entryCount; - entry->size = size; - if (m_index + size > b2_stackSize) - { - entry->data = (char*)b2Alloc(size); - entry->usedMalloc = true; - } - else - { - entry->data = m_data + m_index; - entry->usedMalloc = false; - m_index += size; - } - - m_allocation += size; - m_maxAllocation = b2Max(m_maxAllocation, m_allocation); - ++m_entryCount; - - return entry->data; -} - -void b2StackAllocator::Free(void* p) -{ - b2Assert(m_entryCount > 0); - b2StackEntry* entry = m_entries + m_entryCount - 1; - b2Assert(p == entry->data); - if (entry->usedMalloc) - { - b2Free(p); - } - else - { - m_index -= entry->size; - } - m_allocation -= entry->size; - --m_entryCount; - - p = NULL; -} - -int32 b2StackAllocator::GetMaxAllocation() const -{ - return m_maxAllocation; -} diff --git a/external/box2d/Common/b2StackAllocator.h b/external/box2d/Common/b2StackAllocator.h deleted file mode 100644 index 6140d0d802..0000000000 --- a/external/box2d/Common/b2StackAllocator.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_STACK_ALLOCATOR_H -#define B2_STACK_ALLOCATOR_H - -#include - -const int32 b2_stackSize = 100 * 1024; // 100k -const int32 b2_maxStackEntries = 32; - -struct b2StackEntry -{ - char* data; - int32 size; - bool usedMalloc; -}; - -// This is a stack allocator used for fast per step allocations. -// You must nest allocate/free pairs. The code will assert -// if you try to interleave multiple allocate/free pairs. -class b2StackAllocator -{ -public: - b2StackAllocator(); - ~b2StackAllocator(); - - void* Allocate(int32 size); - void Free(void* p); - - int32 GetMaxAllocation() const; - -private: - - char m_data[b2_stackSize]; - int32 m_index; - - int32 m_allocation; - int32 m_maxAllocation; - - b2StackEntry m_entries[b2_maxStackEntries]; - int32 m_entryCount; -}; - -#endif diff --git a/external/box2d/Common/b2Timer.cpp b/external/box2d/Common/b2Timer.cpp deleted file mode 100644 index b2bee94513..0000000000 --- a/external/box2d/Common/b2Timer.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -#if defined(_WIN32) && !defined(SHP) - -float64 b2Timer::s_invFrequency = 0.0f; - -#include - -b2Timer::b2Timer() -{ - LARGE_INTEGER largeInteger; - - if (s_invFrequency == 0.0f) - { - QueryPerformanceFrequency(&largeInteger); - s_invFrequency = float64(largeInteger.QuadPart); - if (s_invFrequency > 0.0f) - { - s_invFrequency = 1000.0f / s_invFrequency; - } - } - - QueryPerformanceCounter(&largeInteger); - m_start = float64(largeInteger.QuadPart); -} - -void b2Timer::Reset() -{ - LARGE_INTEGER largeInteger; - QueryPerformanceCounter(&largeInteger); - m_start = float64(largeInteger.QuadPart); -} - -float32 b2Timer::GetMilliseconds() const -{ - LARGE_INTEGER largeInteger; - QueryPerformanceCounter(&largeInteger); - float64 count = float64(largeInteger.QuadPart); - float32 ms = float32(s_invFrequency * (count - m_start)); - return ms; -} - -#elif defined(__linux__) || defined (__APPLE__) - -#include - -b2Timer::b2Timer() -{ - Reset(); -} - -void b2Timer::Reset() -{ - timeval t; - gettimeofday(&t, 0); - m_start_sec = t.tv_sec; - m_start_msec = t.tv_usec * 0.001f; -} - -float32 b2Timer::GetMilliseconds() const -{ - timeval t; - gettimeofday(&t, 0); - return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; -} - -#else - -b2Timer::b2Timer() -{ -} - -void b2Timer::Reset() -{ -} - -float32 b2Timer::GetMilliseconds() const -{ - return 0.0f; -} - -#endif diff --git a/external/box2d/Common/b2Timer.h b/external/box2d/Common/b2Timer.h deleted file mode 100644 index 053a107a56..0000000000 --- a/external/box2d/Common/b2Timer.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 - -/// Timer for profiling. This has platform specific code and may -/// not work on every platform. -class b2Timer -{ -public: - - /// Constructor - b2Timer(); - - /// Reset the timer. - void Reset(); - - /// Get the time since construction or the last reset. - float32 GetMilliseconds() const; - -private: - -#if defined(_WIN32) - float64 m_start; - static float64 s_invFrequency; -#elif defined(__linux__) || defined (__APPLE__) - unsigned long m_start_sec; - unsigned long m_start_msec; -#endif -}; diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp deleted file mode 100644 index 4ae4c41cd3..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); - return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); -} - -void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); - allocator->Free(contact, sizeof(b2ChainAndCircleContact)); -} - -b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) -: b2Contact(fixtureA, indexA, fixtureB, indexB) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); - b2EdgeShape edge; - chain->GetChildEdge(&edge, m_indexA); - b2CollideEdgeAndCircle( manifold, &edge, xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h deleted file mode 100644 index 1cf601a61f..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ChainAndCircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H -#define B2_CHAIN_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2ChainAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - ~b2ChainAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp deleted file mode 100644 index 8116c34d1b..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); - return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); -} - -void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); - allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); -} - -b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) -: b2Contact(fixtureA, indexA, fixtureB, indexB) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); - b2EdgeShape edge; - chain->GetChildEdge(&edge, m_indexA); - b2CollideEdgeAndPolygon( manifold, &edge, xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h b/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h deleted file mode 100644 index 381c49b844..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H -#define B2_CHAIN_AND_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2ChainAndPolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - ~b2ChainAndPolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2CircleContact.cpp b/external/box2d/Dynamics/Contacts/b2CircleContact.cpp deleted file mode 100644 index 2436da5132..0000000000 --- a/external/box2d/Dynamics/Contacts/b2CircleContact.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2CircleContact)); - return new (mem) b2CircleContact(fixtureA, fixtureB); -} - -void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2CircleContact*)contact)->~b2CircleContact(); - allocator->Free(contact, sizeof(b2CircleContact)); -} - -b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) - : b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideCircles(manifold, - (b2CircleShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2CircleContact.h b/external/box2d/Dynamics/Contacts/b2CircleContact.h deleted file mode 100644 index 6da056ae0d..0000000000 --- a/external/box2d/Dynamics/Contacts/b2CircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CIRCLE_CONTACT_H -#define B2_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2CircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2CircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2Contact.cpp b/external/box2d/Dynamics/Contacts/b2Contact.cpp deleted file mode 100644 index 2389af6434..0000000000 --- a/external/box2d/Dynamics/Contacts/b2Contact.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; -bool b2Contact::s_initialized = false; - -void b2Contact::InitializeRegisters() -{ - AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); - AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); - AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); - AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); - AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); - AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); - AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); -} - -void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, - b2Shape::Type type1, b2Shape::Type type2) -{ - b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); - b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); - - s_registers[type1][type2].createFcn = createFcn; - s_registers[type1][type2].destroyFcn = destoryFcn; - s_registers[type1][type2].primary = true; - - if (type1 != type2) - { - s_registers[type2][type1].createFcn = createFcn; - s_registers[type2][type1].destroyFcn = destoryFcn; - s_registers[type2][type1].primary = false; - } -} - -b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) -{ - if (s_initialized == false) - { - InitializeRegisters(); - s_initialized = true; - } - - b2Shape::Type type1 = fixtureA->GetType(); - b2Shape::Type type2 = fixtureB->GetType(); - - b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); - b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); - - b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; - if (createFcn) - { - if (s_registers[type1][type2].primary) - { - return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); - } - else - { - return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); - } - } - else - { - return NULL; - } -} - -void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - b2Assert(s_initialized == true); - - if (contact->m_manifold.pointCount > 0) - { - contact->GetFixtureA()->GetBody()->SetAwake(true); - contact->GetFixtureB()->GetBody()->SetAwake(true); - } - - b2Shape::Type typeA = contact->GetFixtureA()->GetType(); - b2Shape::Type typeB = contact->GetFixtureB()->GetType(); - - b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); - b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); - - b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; - destroyFcn(contact, allocator); -} - -b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) -{ - m_flags = e_enabledFlag; - - m_fixtureA = fA; - m_fixtureB = fB; - - m_indexA = indexA; - m_indexB = indexB; - - m_manifold.pointCount = 0; - - m_prev = NULL; - m_next = NULL; - - m_nodeA.contact = NULL; - m_nodeA.prev = NULL; - m_nodeA.next = NULL; - m_nodeA.other = NULL; - - m_nodeB.contact = NULL; - m_nodeB.prev = NULL; - m_nodeB.next = NULL; - m_nodeB.other = NULL; - - m_toiCount = 0; - - m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); - m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); -} - -// Update the contact manifold and touching status. -// Note: do not assume the fixture AABBs are overlapping or are valid. -void b2Contact::Update(b2ContactListener* listener) -{ - b2Manifold oldManifold = m_manifold; - - // Re-enable this contact. - m_flags |= e_enabledFlag; - - bool touching = false; - bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; - - bool sensorA = m_fixtureA->IsSensor(); - bool sensorB = m_fixtureB->IsSensor(); - bool sensor = sensorA || sensorB; - - b2Body* bodyA = m_fixtureA->GetBody(); - b2Body* bodyB = m_fixtureB->GetBody(); - const b2Transform& xfA = bodyA->GetTransform(); - const b2Transform& xfB = bodyB->GetTransform(); - - // Is this contact a sensor? - if (sensor) - { - const b2Shape* shapeA = m_fixtureA->GetShape(); - const b2Shape* shapeB = m_fixtureB->GetShape(); - touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); - - // Sensors don't generate manifolds. - m_manifold.pointCount = 0; - } - else - { - Evaluate(&m_manifold, xfA, xfB); - touching = m_manifold.pointCount > 0; - - // Match old contact ids to new contact ids and copy the - // stored impulses to warm start the solver. - for (int32 i = 0; i < m_manifold.pointCount; ++i) - { - b2ManifoldPoint* mp2 = m_manifold.points + i; - mp2->normalImpulse = 0.0f; - mp2->tangentImpulse = 0.0f; - b2ContactID id2 = mp2->id; - - for (int32 j = 0; j < oldManifold.pointCount; ++j) - { - b2ManifoldPoint* mp1 = oldManifold.points + j; - - if (mp1->id.key == id2.key) - { - mp2->normalImpulse = mp1->normalImpulse; - mp2->tangentImpulse = mp1->tangentImpulse; - break; - } - } - } - - if (touching != wasTouching) - { - bodyA->SetAwake(true); - bodyB->SetAwake(true); - } - } - - if (touching) - { - m_flags |= e_touchingFlag; - } - else - { - m_flags &= ~e_touchingFlag; - } - - if (wasTouching == false && touching == true && listener) - { - listener->BeginContact(this); - } - - if (wasTouching == true && touching == false && listener) - { - listener->EndContact(this); - } - - if (sensor == false && touching && listener) - { - listener->PreSolve(this, &oldManifold); - } -} diff --git a/external/box2d/Dynamics/Contacts/b2Contact.h b/external/box2d/Dynamics/Contacts/b2Contact.h deleted file mode 100644 index 20d9403ce7..0000000000 --- a/external/box2d/Dynamics/Contacts/b2Contact.h +++ /dev/null @@ -1,331 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_H -#define B2_CONTACT_H - -#include -#include -#include -#include - -class b2Body; -class b2Contact; -class b2Fixture; -class b2World; -class b2BlockAllocator; -class b2StackAllocator; -class b2ContactListener; - -/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. -/// For example, anything slides on ice. -inline float32 b2MixFriction(float32 friction1, float32 friction2) -{ - return std::sqrt(friction1 * friction2); -} - -/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. -/// For example, a superball bounces on anything. -inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) -{ - return restitution1 > restitution2 ? restitution1 : restitution2; -} - -typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, - b2BlockAllocator* allocator); -typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); - -struct b2ContactRegister -{ - b2ContactCreateFcn* createFcn; - b2ContactDestroyFcn* destroyFcn; - bool primary; -}; - -/// A contact edge is used to connect bodies and contacts together -/// in a contact graph where each body is a node and each contact -/// is an edge. A contact edge belongs to a doubly linked list -/// maintained in each attached body. Each contact has two contact -/// nodes, one for each attached body. -struct b2ContactEdge -{ - b2Body* other; ///< provides quick access to the other body attached. - b2Contact* contact; ///< the contact - b2ContactEdge* prev; ///< the previous contact edge in the body's contact list - b2ContactEdge* next; ///< the next contact edge in the body's contact list -}; - -/// The class manages contact between two shapes. A contact exists for each overlapping -/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist -/// that has no contact points. -class b2Contact -{ -public: - - /// Get the contact manifold. Do not modify the manifold unless you understand the - /// internals of Box2D. - b2Manifold* GetManifold(); - const b2Manifold* GetManifold() const; - - /// Get the world manifold. - void GetWorldManifold(b2WorldManifold* worldManifold) const; - - /// Is this contact touching? - bool IsTouching() const; - - /// Enable/disable this contact. This can be used inside the pre-solve - /// contact listener. The contact is only disabled for the current - /// time step (or sub-step in continuous collisions). - void SetEnabled(bool flag); - - /// Has this contact been disabled? - bool IsEnabled() const; - - /// Get the next contact in the world's contact list. - b2Contact* GetNext(); - const b2Contact* GetNext() const; - - /// Get fixture A in this contact. - b2Fixture* GetFixtureA(); - const b2Fixture* GetFixtureA() const; - - /// Get the child primitive index for fixture A. - int32 GetChildIndexA() const; - - /// Get fixture B in this contact. - b2Fixture* GetFixtureB(); - const b2Fixture* GetFixtureB() const; - - /// Get the child primitive index for fixture B. - int32 GetChildIndexB() const; - - /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. - /// This value persists until set or reset. - void SetFriction(float32 friction); - - /// Get the friction. - float32 GetFriction() const; - - /// Reset the friction mixture to the default value. - void ResetFriction(); - - /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. - /// The value persists until you set or reset. - void SetRestitution(float32 restitution); - - /// Get the restitution. - float32 GetRestitution() const; - - /// Reset the restitution to the default value. - void ResetRestitution(); - - /// Evaluate this contact with your own manifold and transforms. - virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; - -protected: - friend class b2ContactManager; - friend class b2World; - friend class b2ContactSolver; - friend class b2Body; - friend class b2Fixture; - - // Flags stored in m_flags - enum - { - // Used when crawling contact graph when forming islands. - e_islandFlag = 0x0001, - - // Set when the shapes are touching. - e_touchingFlag = 0x0002, - - // This contact can be disabled (by user) - e_enabledFlag = 0x0004, - - // This contact needs filtering because a fixture filter was changed. - e_filterFlag = 0x0008, - - // This bullet contact had a TOI event - e_bulletHitFlag = 0x0010, - - // This contact has a valid TOI in m_toi - e_toiFlag = 0x0020 - }; - - /// Flag this contact for filtering. Filtering will occur the next time step. - void FlagForFiltering(); - - static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, - b2Shape::Type typeA, b2Shape::Type typeB); - static void InitializeRegisters(); - static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} - b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); - virtual ~b2Contact() {} - - void Update(b2ContactListener* listener); - - static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; - static bool s_initialized; - - uint32 m_flags; - - // World pool and list pointers. - b2Contact* m_prev; - b2Contact* m_next; - - // Nodes for connecting bodies. - b2ContactEdge m_nodeA; - b2ContactEdge m_nodeB; - - b2Fixture* m_fixtureA; - b2Fixture* m_fixtureB; - - int32 m_indexA; - int32 m_indexB; - - b2Manifold m_manifold; - - int32 m_toiCount; - float32 m_toi; - - float32 m_friction; - float32 m_restitution; -}; - -inline b2Manifold* b2Contact::GetManifold() -{ - return &m_manifold; -} - -inline const b2Manifold* b2Contact::GetManifold() const -{ - return &m_manifold; -} - -inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const -{ - const b2Body* bodyA = m_fixtureA->GetBody(); - const b2Body* bodyB = m_fixtureB->GetBody(); - const b2Shape* shapeA = m_fixtureA->GetShape(); - const b2Shape* shapeB = m_fixtureB->GetShape(); - - worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); -} - -inline void b2Contact::SetEnabled(bool flag) -{ - if (flag) - { - m_flags |= e_enabledFlag; - } - else - { - m_flags &= ~e_enabledFlag; - } -} - -inline bool b2Contact::IsEnabled() const -{ - return (m_flags & e_enabledFlag) == e_enabledFlag; -} - -inline bool b2Contact::IsTouching() const -{ - return (m_flags & e_touchingFlag) == e_touchingFlag; -} - -inline b2Contact* b2Contact::GetNext() -{ - return m_next; -} - -inline const b2Contact* b2Contact::GetNext() const -{ - return m_next; -} - -inline b2Fixture* b2Contact::GetFixtureA() -{ - return m_fixtureA; -} - -inline const b2Fixture* b2Contact::GetFixtureA() const -{ - return m_fixtureA; -} - -inline b2Fixture* b2Contact::GetFixtureB() -{ - return m_fixtureB; -} - -inline int32 b2Contact::GetChildIndexA() const -{ - return m_indexA; -} - -inline const b2Fixture* b2Contact::GetFixtureB() const -{ - return m_fixtureB; -} - -inline int32 b2Contact::GetChildIndexB() const -{ - return m_indexB; -} - -inline void b2Contact::FlagForFiltering() -{ - m_flags |= e_filterFlag; -} - -inline void b2Contact::SetFriction(float32 friction) -{ - m_friction = friction; -} - -inline float32 b2Contact::GetFriction() const -{ - return m_friction; -} - -inline void b2Contact::ResetFriction() -{ - m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); -} - -inline void b2Contact::SetRestitution(float32 restitution) -{ - m_restitution = restitution; -} - -inline float32 b2Contact::GetRestitution() const -{ - return m_restitution; -} - -inline void b2Contact::ResetRestitution() -{ - m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); -} - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp b/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp deleted file mode 100644 index 0dc740342a..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ContactSolver.cpp +++ /dev/null @@ -1,832 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 - -#include -#include -#include -#include -#include - -#define B2_DEBUG_SOLVER 0 - -struct b2ContactPositionConstraint -{ - b2Vec2 localPoints[b2_maxManifoldPoints]; - b2Vec2 localNormal; - b2Vec2 localPoint; - int32 indexA; - int32 indexB; - float32 invMassA, invMassB; - b2Vec2 localCenterA, localCenterB; - float32 invIA, invIB; - b2Manifold::Type type; - float32 radiusA, radiusB; - int32 pointCount; -}; - -b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) -{ - m_step = def->step; - m_allocator = def->allocator; - m_count = def->count; - m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); - m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); - m_positions = def->positions; - m_velocities = def->velocities; - m_contacts = def->contacts; - - // Initialize position independent portions of the constraints. - for (int32 i = 0; i < m_count; ++i) - { - b2Contact* contact = m_contacts[i]; - - b2Fixture* fixtureA = contact->m_fixtureA; - b2Fixture* fixtureB = contact->m_fixtureB; - b2Shape* shapeA = fixtureA->GetShape(); - b2Shape* shapeB = fixtureB->GetShape(); - float32 radiusA = shapeA->m_radius; - float32 radiusB = shapeB->m_radius; - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - b2Manifold* manifold = contact->GetManifold(); - - int32 pointCount = manifold->pointCount; - b2Assert(pointCount > 0); - - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - vc->friction = contact->m_friction; - vc->restitution = contact->m_restitution; - vc->indexA = bodyA->m_islandIndex; - vc->indexB = bodyB->m_islandIndex; - vc->invMassA = bodyA->m_invMass; - vc->invMassB = bodyB->m_invMass; - vc->invIA = bodyA->m_invI; - vc->invIB = bodyB->m_invI; - vc->contactIndex = i; - vc->pointCount = pointCount; - vc->K.SetZero(); - vc->normalMass.SetZero(); - - b2ContactPositionConstraint* pc = m_positionConstraints + i; - pc->indexA = bodyA->m_islandIndex; - pc->indexB = bodyB->m_islandIndex; - pc->invMassA = bodyA->m_invMass; - pc->invMassB = bodyB->m_invMass; - pc->localCenterA = bodyA->m_sweep.localCenter; - pc->localCenterB = bodyB->m_sweep.localCenter; - pc->invIA = bodyA->m_invI; - pc->invIB = bodyB->m_invI; - pc->localNormal = manifold->localNormal; - pc->localPoint = manifold->localPoint; - pc->pointCount = pointCount; - pc->radiusA = radiusA; - pc->radiusB = radiusB; - pc->type = manifold->type; - - for (int32 j = 0; j < pointCount; ++j) - { - b2ManifoldPoint* cp = manifold->points + j; - b2VelocityConstraintPoint* vcp = vc->points + j; - - if (m_step.warmStarting) - { - vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; - vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; - } - else - { - vcp->normalImpulse = 0.0f; - vcp->tangentImpulse = 0.0f; - } - - vcp->rA.SetZero(); - vcp->rB.SetZero(); - vcp->normalMass = 0.0f; - vcp->tangentMass = 0.0f; - vcp->velocityBias = 0.0f; - - pc->localPoints[j] = cp->localPoint; - } - } -} - -b2ContactSolver::~b2ContactSolver() -{ - m_allocator->Free(m_velocityConstraints); - m_allocator->Free(m_positionConstraints); -} - -// Initialize position dependent portions of the velocity constraints. -void b2ContactSolver::InitializeVelocityConstraints() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - float32 radiusA = pc->radiusA; - float32 radiusB = pc->radiusB; - b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - - float32 mA = vc->invMassA; - float32 mB = vc->invMassB; - float32 iA = vc->invIA; - float32 iB = vc->invIB; - b2Vec2 localCenterA = pc->localCenterA; - b2Vec2 localCenterB = pc->localCenterB; - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Assert(manifold->pointCount > 0); - - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2WorldManifold worldManifold; - worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); - - vc->normal = worldManifold.normal; - - int32 pointCount = vc->pointCount; - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - - vcp->rA = worldManifold.points[j] - cA; - vcp->rB = worldManifold.points[j] - cB; - - float32 rnA = b2Cross(vcp->rA, vc->normal); - float32 rnB = b2Cross(vcp->rB, vc->normal); - - float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; - - b2Vec2 tangent = b2Cross(vc->normal, 1.0f); - - float32 rtA = b2Cross(vcp->rA, tangent); - float32 rtB = b2Cross(vcp->rB, tangent); - - float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; - - vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; - - // Setup a velocity bias for restitution. - vcp->velocityBias = 0.0f; - float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); - if (vRel < -b2_velocityThreshold) - { - vcp->velocityBias = -vc->restitution * vRel; - } - } - - // If we have two points, then prepare the block solver. - if (vc->pointCount == 2) - { - b2VelocityConstraintPoint* vcp1 = vc->points + 0; - b2VelocityConstraintPoint* vcp2 = vc->points + 1; - - float32 rn1A = b2Cross(vcp1->rA, vc->normal); - float32 rn1B = b2Cross(vcp1->rB, vc->normal); - float32 rn2A = b2Cross(vcp2->rA, vc->normal); - float32 rn2B = b2Cross(vcp2->rB, vc->normal); - - float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; - float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; - float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; - - // Ensure a reasonable condition number. - const float32 k_maxConditionNumber = 1000.0f; - if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) - { - // K is safe to invert. - vc->K.ex.Set(k11, k12); - vc->K.ey.Set(k12, k22); - vc->normalMass = vc->K.GetInverse(); - } - else - { - // The constraints are redundant, just use one. - // TODO_ERIN use deepest? - vc->pointCount = 1; - } - } - } -} - -void b2ContactSolver::WarmStart() -{ - // Warm start. - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - float32 mA = vc->invMassA; - float32 iA = vc->invIA; - float32 mB = vc->invMassB; - float32 iB = vc->invIB; - int32 pointCount = vc->pointCount; - - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Vec2 normal = vc->normal; - b2Vec2 tangent = b2Cross(normal, 1.0f); - - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; - wA -= iA * b2Cross(vcp->rA, P); - vA -= mA * P; - wB += iB * b2Cross(vcp->rB, P); - vB += mB * P; - } - - m_velocities[indexA].v = vA; - m_velocities[indexA].w = wA; - m_velocities[indexB].v = vB; - m_velocities[indexB].w = wB; - } -} - -void b2ContactSolver::SolveVelocityConstraints() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - - int32 indexA = vc->indexA; - int32 indexB = vc->indexB; - float32 mA = vc->invMassA; - float32 iA = vc->invIA; - float32 mB = vc->invMassB; - float32 iB = vc->invIB; - int32 pointCount = vc->pointCount; - - b2Vec2 vA = m_velocities[indexA].v; - float32 wA = m_velocities[indexA].w; - b2Vec2 vB = m_velocities[indexB].v; - float32 wB = m_velocities[indexB].w; - - b2Vec2 normal = vc->normal; - b2Vec2 tangent = b2Cross(normal, 1.0f); - float32 friction = vc->friction; - - b2Assert(pointCount == 1 || pointCount == 2); - - // Solve tangent constraints first because non-penetration is more important - // than friction. - for (int32 j = 0; j < pointCount; ++j) - { - b2VelocityConstraintPoint* vcp = vc->points + j; - - // Relative velocity at contact - b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); - - // Compute tangent force - float32 vt = b2Dot(dv, tangent); - float32 lambda = vcp->tangentMass * (-vt); - - // b2Clamp the accumulated force - float32 maxFriction = friction * vcp->normalImpulse; - float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); - lambda = newImpulse - vcp->tangentImpulse; - vcp->tangentImpulse = newImpulse; - - // Apply contact impulse - b2Vec2 P = lambda * tangent; - - vA -= mA * P; - wA -= iA * b2Cross(vcp->rA, P); - - vB += mB * P; - wB += iB * b2Cross(vcp->rB, P); - } - - // Solve normal constraints - if (vc->pointCount == 1) - { - b2VelocityConstraintPoint* vcp = vc->points + 0; - - // Relative velocity at contact - b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); - - // Compute normal impulse - float32 vn = b2Dot(dv, normal); - float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); - - // b2Clamp the accumulated impulse - float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); - lambda = newImpulse - vcp->normalImpulse; - vcp->normalImpulse = newImpulse; - - // Apply contact impulse - b2Vec2 P = lambda * normal; - vA -= mA * P; - wA -= iA * b2Cross(vcp->rA, P); - - vB += mB * P; - wB += iB * b2Cross(vcp->rB, P); - } - else - { - // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). - // Build the mini LCP for this contact patch - // - // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 - // - // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) - // b = vn0 - velocityBias - // - // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i - // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases - // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid - // solution that satisfies the problem is chosen. - // - // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires - // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). - // - // Substitute: - // - // x = a + d - // - // a := old total impulse - // x := new total impulse - // d := incremental impulse - // - // For the current iteration we extend the formula for the incremental impulse - // to compute the new total impulse: - // - // vn = A * d + b - // = A * (x - a) + b - // = A * x + b - A * a - // = A * x + b' - // b' = b - A * a; - - b2VelocityConstraintPoint* cp1 = vc->points + 0; - b2VelocityConstraintPoint* cp2 = vc->points + 1; - - b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); - b2Assert(a.x >= 0.0f && a.y >= 0.0f); - - // Relative velocity at contact - b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - float32 vn1 = b2Dot(dv1, normal); - float32 vn2 = b2Dot(dv2, normal); - - b2Vec2 b; - b.x = vn1 - cp1->velocityBias; - b.y = vn2 - cp2->velocityBias; - - // Compute b' - b -= b2Mul(vc->K, a); - - const float32 k_errorTol = 1e-3f; - B2_NOT_USED(k_errorTol); - - for (;;) - { - // - // Case 1: vn = 0 - // - // 0 = A * x + b' - // - // Solve for x: - // - // x = - inv(A) * b' - // - b2Vec2 x = - b2Mul(vc->normalMass, b); - - if (x.x >= 0.0f && x.y >= 0.0f) - { - // Get the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - vn1 = b2Dot(dv1, normal); - vn2 = b2Dot(dv2, normal); - - b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); - b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); -#endif - break; - } - - // - // Case 2: vn1 = 0 and x2 = 0 - // - // 0 = a11 * x1 + a12 * 0 + b1' - // vn2 = a21 * x1 + a22 * 0 + b2' - // - x.x = - cp1->normalMass * b.x; - x.y = 0.0f; - vn1 = 0.0f; - vn2 = vc->K.ex.y * x.x + b.y; - - if (x.x >= 0.0f && vn2 >= 0.0f) - { - // Get the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); - - // Compute normal velocity - vn1 = b2Dot(dv1, normal); - - b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); -#endif - break; - } - - - // - // Case 3: vn2 = 0 and x1 = 0 - // - // vn1 = a11 * 0 + a12 * x2 + b1' - // 0 = a21 * 0 + a22 * x2 + b2' - // - x.x = 0.0f; - x.y = - cp2->normalMass * b.y; - vn1 = vc->K.ey.x * x.y + b.x; - vn2 = 0.0f; - - if (x.y >= 0.0f && vn1 >= 0.0f) - { - // Resubstitute for the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - -#if B2_DEBUG_SOLVER == 1 - // Postconditions - dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); - - // Compute normal velocity - vn2 = b2Dot(dv2, normal); - - b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); -#endif - break; - } - - // - // Case 4: x1 = 0 and x2 = 0 - // - // vn1 = b1 - // vn2 = b2; - x.x = 0.0f; - x.y = 0.0f; - vn1 = b.x; - vn2 = b.y; - - if (vn1 >= 0.0f && vn2 >= 0.0f ) - { - // Resubstitute for the incremental impulse - b2Vec2 d = x - a; - - // Apply incremental impulse - b2Vec2 P1 = d.x * normal; - b2Vec2 P2 = d.y * normal; - vA -= mA * (P1 + P2); - wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); - - vB += mB * (P1 + P2); - wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); - - // Accumulate - cp1->normalImpulse = x.x; - cp2->normalImpulse = x.y; - - break; - } - - // No solution, give up. This is hit sometimes, but it doesn't seem to matter. - break; - } - } - - m_velocities[indexA].v = vA; - m_velocities[indexA].w = wA; - m_velocities[indexB].v = vB; - m_velocities[indexB].w = wB; - } -} - -void b2ContactSolver::StoreImpulses() -{ - for (int32 i = 0; i < m_count; ++i) - { - b2ContactVelocityConstraint* vc = m_velocityConstraints + i; - b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); - - for (int32 j = 0; j < vc->pointCount; ++j) - { - manifold->points[j].normalImpulse = vc->points[j].normalImpulse; - manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; - } - } -} - -struct b2PositionSolverManifold -{ - void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) - { - b2Assert(pc->pointCount > 0); - - switch (pc->type) - { - case b2Manifold::e_circles: - { - b2Vec2 pointA = b2Mul(xfA, pc->localPoint); - b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); - normal = pointB - pointA; - normal.Normalize(); - point = 0.5f * (pointA + pointB); - separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; - } - break; - - case b2Manifold::e_faceA: - { - normal = b2Mul(xfA.q, pc->localNormal); - b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); - - b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); - separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; - point = clipPoint; - } - break; - - case b2Manifold::e_faceB: - { - normal = b2Mul(xfB.q, pc->localNormal); - b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); - - b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); - separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; - point = clipPoint; - - // Ensure normal points from A to B - normal = -normal; - } - break; - } - } - - b2Vec2 normal; - b2Vec2 point; - float32 separation; -}; - -// Sequential solver. -bool b2ContactSolver::SolvePositionConstraints() -{ - float32 minSeparation = 0.0f; - - for (int32 i = 0; i < m_count; ++i) - { - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - int32 indexA = pc->indexA; - int32 indexB = pc->indexB; - b2Vec2 localCenterA = pc->localCenterA; - float32 mA = pc->invMassA; - float32 iA = pc->invIA; - b2Vec2 localCenterB = pc->localCenterB; - float32 mB = pc->invMassB; - float32 iB = pc->invIB; - int32 pointCount = pc->pointCount; - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - - // Solve normal constraints - for (int32 j = 0; j < pointCount; ++j) - { - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2PositionSolverManifold psm; - psm.Initialize(pc, xfA, xfB, j); - b2Vec2 normal = psm.normal; - - b2Vec2 point = psm.point; - float32 separation = psm.separation; - - b2Vec2 rA = point - cA; - b2Vec2 rB = point - cB; - - // Track max constraint error. - minSeparation = b2Min(minSeparation, separation); - - // Prevent large corrections and allow slop. - float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); - - // Compute the effective mass. - float32 rnA = b2Cross(rA, normal); - float32 rnB = b2Cross(rB, normal); - float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - // Compute normal impulse - float32 impulse = K > 0.0f ? - C / K : 0.0f; - - b2Vec2 P = impulse * normal; - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - - m_positions[indexA].c = cA; - m_positions[indexA].a = aA; - - m_positions[indexB].c = cB; - m_positions[indexB].a = aB; - } - - // We can't expect minSpeparation >= -b2_linearSlop because we don't - // push the separation above -b2_linearSlop. - return minSeparation >= -3.0f * b2_linearSlop; -} - -// Sequential position solver for position constraints. -bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) -{ - float32 minSeparation = 0.0f; - - for (int32 i = 0; i < m_count; ++i) - { - b2ContactPositionConstraint* pc = m_positionConstraints + i; - - int32 indexA = pc->indexA; - int32 indexB = pc->indexB; - b2Vec2 localCenterA = pc->localCenterA; - b2Vec2 localCenterB = pc->localCenterB; - int32 pointCount = pc->pointCount; - - float32 mA = 0.0f; - float32 iA = 0.0f; - if (indexA == toiIndexA || indexA == toiIndexB) - { - mA = pc->invMassA; - iA = pc->invIA; - } - - float32 mB = pc->invMassB; - float32 iB = pc->invIB; - if (indexB == toiIndexA || indexB == toiIndexB) - { - mB = pc->invMassB; - iB = pc->invIB; - } - - b2Vec2 cA = m_positions[indexA].c; - float32 aA = m_positions[indexA].a; - - b2Vec2 cB = m_positions[indexB].c; - float32 aB = m_positions[indexB].a; - - // Solve normal constraints - for (int32 j = 0; j < pointCount; ++j) - { - b2Transform xfA, xfB; - xfA.q.Set(aA); - xfB.q.Set(aB); - xfA.p = cA - b2Mul(xfA.q, localCenterA); - xfB.p = cB - b2Mul(xfB.q, localCenterB); - - b2PositionSolverManifold psm; - psm.Initialize(pc, xfA, xfB, j); - b2Vec2 normal = psm.normal; - - b2Vec2 point = psm.point; - float32 separation = psm.separation; - - b2Vec2 rA = point - cA; - b2Vec2 rB = point - cB; - - // Track max constraint error. - minSeparation = b2Min(minSeparation, separation); - - // Prevent large corrections and allow slop. - float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); - - // Compute the effective mass. - float32 rnA = b2Cross(rA, normal); - float32 rnB = b2Cross(rB, normal); - float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; - - // Compute normal impulse - float32 impulse = K > 0.0f ? - C / K : 0.0f; - - b2Vec2 P = impulse * normal; - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - - m_positions[indexA].c = cA; - m_positions[indexA].a = aA; - - m_positions[indexB].c = cB; - m_positions[indexB].a = aB; - } - - // We can't expect minSpeparation >= -b2_linearSlop because we don't - // push the separation above -b2_linearSlop. - return minSeparation >= -1.5f * b2_linearSlop; -} diff --git a/external/box2d/Dynamics/Contacts/b2ContactSolver.h b/external/box2d/Dynamics/Contacts/b2ContactSolver.h deleted file mode 100644 index aef1987a9e..0000000000 --- a/external/box2d/Dynamics/Contacts/b2ContactSolver.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_SOLVER_H -#define B2_CONTACT_SOLVER_H - -#include -#include -#include - -class b2Contact; -class b2Body; -class b2StackAllocator; -struct b2ContactPositionConstraint; - -struct b2VelocityConstraintPoint -{ - b2Vec2 rA; - b2Vec2 rB; - float32 normalImpulse; - float32 tangentImpulse; - float32 normalMass; - float32 tangentMass; - float32 velocityBias; -}; - -struct b2ContactVelocityConstraint -{ - b2VelocityConstraintPoint points[b2_maxManifoldPoints]; - b2Vec2 normal; - b2Mat22 normalMass; - b2Mat22 K; - int32 indexA; - int32 indexB; - float32 invMassA, invMassB; - float32 invIA, invIB; - float32 friction; - float32 restitution; - int32 pointCount; - int32 contactIndex; -}; - -struct b2ContactSolverDef -{ - b2TimeStep step; - b2Contact** contacts; - int32 count; - b2Position* positions; - b2Velocity* velocities; - b2StackAllocator* allocator; -}; - -class b2ContactSolver -{ -public: - b2ContactSolver(b2ContactSolverDef* def); - ~b2ContactSolver(); - - void InitializeVelocityConstraints(); - - void WarmStart(); - void SolveVelocityConstraints(); - void StoreImpulses(); - - bool SolvePositionConstraints(); - bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); - - b2TimeStep m_step; - b2Position* m_positions; - b2Velocity* m_velocities; - b2StackAllocator* m_allocator; - b2ContactPositionConstraint* m_positionConstraints; - b2ContactVelocityConstraint* m_velocityConstraints; - b2Contact** m_contacts; - int m_count; -}; - -#endif - diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp deleted file mode 100644 index aade42880a..0000000000 --- a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include - -#include -using namespace std; - -b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); - return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); -} - -void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); - allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); -} - -b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideEdgeAndCircle( manifold, - (b2EdgeShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h deleted file mode 100644 index 70771ec536..0000000000 --- a/external/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H -#define B2_EDGE_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2EdgeAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2EdgeAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp deleted file mode 100644 index 04ce394107..0000000000 --- a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-2010 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 -#include -#include - -#include -using namespace std; - -b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); - return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); -} - -void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); - allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); -} - -b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollideEdgeAndPolygon( manifold, - (b2EdgeShape*)m_fixtureA->GetShape(), xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h deleted file mode 100644 index f65f3acca9..0000000000 --- a/external/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_EDGE_AND_POLYGON_CONTACT_H -#define B2_EDGE_AND_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2EdgeAndPolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2EdgeAndPolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp deleted file mode 100644 index 961b26f38a..0000000000 --- a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include - -#include -using namespace std; - -b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); - return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); -} - -void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); - allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); -} - -b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) -: b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); - b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); -} - -void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollidePolygonAndCircle( manifold, - (b2PolygonShape*)m_fixtureA->GetShape(), xfA, - (b2CircleShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h b/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h deleted file mode 100644 index 7b1a5288b4..0000000000 --- a/external/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H -#define B2_POLYGON_AND_CIRCLE_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2PolygonAndCircleContact : public b2Contact -{ -public: - static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2PolygonAndCircleContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp b/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp deleted file mode 100644 index a2884a440d..0000000000 --- a/external/box2d/Dynamics/Contacts/b2PolygonContact.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include - -#include -using namespace std; - -b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) -{ - void* mem = allocator->Allocate(sizeof(b2PolygonContact)); - return new (mem) b2PolygonContact(fixtureA, fixtureB); -} - -void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) -{ - ((b2PolygonContact*)contact)->~b2PolygonContact(); - allocator->Free(contact, sizeof(b2PolygonContact)); -} - -b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) - : b2Contact(fixtureA, 0, fixtureB, 0) -{ - b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); - b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); -} - -void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) -{ - b2CollidePolygons( manifold, - (b2PolygonShape*)m_fixtureA->GetShape(), xfA, - (b2PolygonShape*)m_fixtureB->GetShape(), xfB); -} diff --git a/external/box2d/Dynamics/Contacts/b2PolygonContact.h b/external/box2d/Dynamics/Contacts/b2PolygonContact.h deleted file mode 100644 index 302684232a..0000000000 --- a/external/box2d/Dynamics/Contacts/b2PolygonContact.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_POLYGON_CONTACT_H -#define B2_POLYGON_CONTACT_H - -#include - -class b2BlockAllocator; - -class b2PolygonContact : public b2Contact -{ -public: - static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, - b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); - static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); - - b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); - ~b2PolygonContact() {} - - void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp b/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp deleted file mode 100644 index b2d4bd006c..0000000000 --- a/external/box2d/Dynamics/Joints/b2DistanceJoint.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// 1-D constrained system -// m (v2 - v1) = lambda -// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. -// x2 = x1 + h * v2 - -// 1-D mass-damper-spring system -// m (v2 - v1) + h * d * v2 + h * k * - -// C = norm(p2 - p1) - L -// u = (p2 - p1) / norm(p2 - p1) -// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) -// J = [-u -cross(r1, u) u cross(r2, u)] -// K = J * invM * JT -// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 - -void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, - const b2Vec2& anchor1, const b2Vec2& anchor2) -{ - bodyA = b1; - bodyB = b2; - localAnchorA = bodyA->GetLocalPoint(anchor1); - localAnchorB = bodyB->GetLocalPoint(anchor2); - b2Vec2 d = anchor2 - anchor1; - length = d.Length(); -} - -b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_length = def->length; - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - m_impulse = 0.0f; - m_gamma = 0.0f; - m_bias = 0.0f; -} - -void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - m_u = cB + m_rB - cA - m_rA; - - // Handle singularity. - float32 length = m_u.Length(); - if (length > b2_linearSlop) - { - m_u *= 1.0f / length; - } - else - { - m_u.Set(0.0f, 0.0f); - } - - float32 crAu = b2Cross(m_rA, m_u); - float32 crBu = b2Cross(m_rB, m_u); - float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; - - // Compute the effective mass matrix. - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - - if (m_frequencyHz > 0.0f) - { - float32 C = length - m_length; - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m_mass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m_mass * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; - m_bias = C * h * k * m_gamma; - - invMass += m_gamma; - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - } - else - { - m_gamma = 0.0f; - m_bias = 0.0f; - } - - if (data.step.warmStarting) - { - // Scale the impulse to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = dot(u, v + cross(w, r)) - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - float32 Cdot = b2Dot(m_u, vpB - vpA); - - float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); - m_impulse += impulse; - - b2Vec2 P = impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) -{ - if (m_frequencyHz > 0.0f) - { - // There is no position correction for soft distance constraints. - return true; - } - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 u = cB + rB - cA - rA; - - float32 length = u.Normalize(); - float32 C = length - m_length; - C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); - - float32 impulse = -m_mass * C; - b2Vec2 P = impulse * u; - - cA -= m_invMassA * P; - aA -= m_invIA * b2Cross(rA, P); - cB += m_invMassB * P; - aB += m_invIB * b2Cross(rB, P); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return b2Abs(C) < b2_linearSlop; -} - -b2Vec2 b2DistanceJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2DistanceJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 F = (inv_dt * m_impulse) * m_u; - return F; -} - -float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -void b2DistanceJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2DistanceJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.length = %.15lef;\n", m_length); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2DistanceJoint.h b/external/box2d/Dynamics/Joints/b2DistanceJoint.h deleted file mode 100644 index fc11476ff9..0000000000 --- a/external/box2d/Dynamics/Joints/b2DistanceJoint.h +++ /dev/null @@ -1,169 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_DISTANCE_JOINT_H -#define B2_DISTANCE_JOINT_H - -#include - -/// Distance joint definition. This requires defining an -/// anchor point on both bodies and the non-zero length of the -/// distance joint. The definition uses local anchor points -/// so that the initial configuration can violate the constraint -/// slightly. This helps when saving and loading a game. -/// @warning Do not use a zero or short length. -struct b2DistanceJointDef : public b2JointDef -{ - b2DistanceJointDef() - { - type = e_distanceJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - length = 1.0f; - frequencyHz = 0.0f; - dampingRatio = 0.0f; - } - - /// Initialize the bodies, anchors, and length using the world - /// anchors. - void Initialize(b2Body* bodyA, b2Body* bodyB, - const b2Vec2& anchorA, const b2Vec2& anchorB); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The natural length between the anchor points. - float32 length; - - /// The mass-spring-damper frequency in Hertz. A value of 0 - /// disables softness. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A distance joint constrains two points on two bodies -/// to remain at a fixed distance from each other. You can view -/// this as a massless, rigid rod. -class b2DistanceJoint : public b2Joint -{ -public: - - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - /// Get the reaction force given the inverse time step. - /// Unit is N. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Get the reaction torque given the inverse time step. - /// Unit is N*m. This is always zero for a distance joint. - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set/get the natural length. - /// Manipulating the length can lead to non-physical behavior when the frequency is zero. - void SetLength(float32 length); - float32 GetLength() const; - - /// Set/get frequency in Hz. - void SetFrequency(float32 hz); - float32 GetFrequency() const; - - /// Set/get damping ratio. - void SetDampingRatio(float32 ratio); - float32 GetDampingRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2DistanceJoint(const b2DistanceJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_bias; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_gamma; - float32 m_impulse; - float32 m_length; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_u; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; -}; - -inline void b2DistanceJoint::SetLength(float32 length) -{ - m_length = length; -} - -inline float32 b2DistanceJoint::GetLength() const -{ - return m_length; -} - -inline void b2DistanceJoint::SetFrequency(float32 hz) -{ - m_frequencyHz = hz; -} - -inline float32 b2DistanceJoint::GetFrequency() const -{ - return m_frequencyHz; -} - -inline void b2DistanceJoint::SetDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -inline float32 b2DistanceJoint::GetDampingRatio() const -{ - return m_dampingRatio; -} - -#endif diff --git a/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp b/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp deleted file mode 100644 index 6e6018db10..0000000000 --- a/external/box2d/Dynamics/Joints/b2FrictionJoint.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Angle constraint -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); -} - -b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_linearImpulse.SetZero(); - m_angularImpulse = 0.0f; - - m_maxForce = def->maxForce; - m_maxTorque = def->maxTorque; -} - -void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective mass matrix. - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat22 K; - K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; - K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; - K.ey.x = K.ex.y; - K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; - - m_linearMass = K.GetInverse(); - - m_angularMass = iA + iB; - if (m_angularMass > 0.0f) - { - m_angularMass = 1.0f / m_angularMass; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_linearImpulse *= data.step.dtRatio; - m_angularImpulse *= data.step.dtRatio; - - b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); - } - else - { - m_linearImpulse.SetZero(); - m_angularImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - float32 h = data.step.dt; - - // Solve angular friction - { - float32 Cdot = wB - wA; - float32 impulse = -m_angularMass * Cdot; - - float32 oldImpulse = m_angularImpulse; - float32 maxImpulse = h * m_maxTorque; - m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_angularImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve linear friction - { - b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - - b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); - b2Vec2 oldImpulse = m_linearImpulse; - m_linearImpulse += impulse; - - float32 maxImpulse = h * m_maxForce; - - if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) - { - m_linearImpulse.Normalize(); - m_linearImpulse *= maxImpulse; - } - - impulse = m_linearImpulse - oldImpulse; - - vA -= mA * impulse; - wA -= iA * b2Cross(m_rA, impulse); - - vB += mB * impulse; - wB += iB * b2Cross(m_rB, impulse); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) -{ - B2_NOT_USED(data); - - return true; -} - -b2Vec2 b2FrictionJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2FrictionJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * m_linearImpulse; -} - -float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_angularImpulse; -} - -void b2FrictionJoint::SetMaxForce(float32 force) -{ - b2Assert(b2IsValid(force) && force >= 0.0f); - m_maxForce = force; -} - -float32 b2FrictionJoint::GetMaxForce() const -{ - return m_maxForce; -} - -void b2FrictionJoint::SetMaxTorque(float32 torque) -{ - b2Assert(b2IsValid(torque) && torque >= 0.0f); - m_maxTorque = torque; -} - -float32 b2FrictionJoint::GetMaxTorque() const -{ - return m_maxTorque; -} - -void b2FrictionJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2FrictionJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); - b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2FrictionJoint.h b/external/box2d/Dynamics/Joints/b2FrictionJoint.h deleted file mode 100644 index 3ee40c6298..0000000000 --- a/external/box2d/Dynamics/Joints/b2FrictionJoint.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_FRICTION_JOINT_H -#define B2_FRICTION_JOINT_H - -#include - -/// Friction joint definition. -struct b2FrictionJointDef : public b2JointDef -{ - b2FrictionJointDef() - { - type = e_frictionJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - maxForce = 0.0f; - maxTorque = 0.0f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The maximum friction force in N. - float32 maxForce; - - /// The maximum friction torque in N-m. - float32 maxTorque; -}; - -/// Friction joint. This is used for top-down friction. -/// It provides 2D translational friction and angular friction. -class b2FrictionJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set the maximum friction force in N. - void SetMaxForce(float32 force); - - /// Get the maximum friction force in N. - float32 GetMaxForce() const; - - /// Set the maximum friction torque in N*m. - void SetMaxTorque(float32 torque); - - /// Get the maximum friction torque in N*m. - float32 GetMaxTorque() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - - b2FrictionJoint(const b2FrictionJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - - // Solver shared - b2Vec2 m_linearImpulse; - float32 m_angularImpulse; - float32 m_maxForce; - float32 m_maxTorque; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat22 m_linearMass; - float32 m_angularMass; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2GearJoint.cpp b/external/box2d/Dynamics/Joints/b2GearJoint.cpp deleted file mode 100644 index 9741cdd5a4..0000000000 --- a/external/box2d/Dynamics/Joints/b2GearJoint.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* -* Copyright (c) 2007-2011 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 -#include -#include -#include -#include - -// Gear Joint: -// C0 = (coordinate1 + ratio * coordinate2)_initial -// C = (coordinate1 + ratio * coordinate2) - C0 = 0 -// J = [J1 ratio * J2] -// K = J * invM * JT -// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T -// -// Revolute: -// coordinate = rotation -// Cdot = angularVelocity -// J = [0 0 1] -// K = J * invM * JT = invI -// -// Prismatic: -// coordinate = dot(p - pg, ug) -// Cdot = dot(v + cross(w, r), ug) -// J = [ug cross(r, ug)] -// K = J * invM * JT = invMass + invI * cross(r, ug)^2 - -b2GearJoint::b2GearJoint(const b2GearJointDef* def) -: b2Joint(def) -{ - m_joint1 = def->joint1; - m_joint2 = def->joint2; - - m_typeA = m_joint1->GetType(); - m_typeB = m_joint2->GetType(); - - b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); - b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); - - float32 coordinateA, coordinateB; - - // TODO_ERIN there might be some problem with the joint edges in b2Joint. - - m_bodyC = m_joint1->GetBodyA(); - m_bodyA = m_joint1->GetBodyB(); - - // Get geometry of joint1 - b2Transform xfA = m_bodyA->m_xf; - float32 aA = m_bodyA->m_sweep.a; - b2Transform xfC = m_bodyC->m_xf; - float32 aC = m_bodyC->m_sweep.a; - - if (m_typeA == e_revoluteJoint) - { - b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; - m_localAnchorC = revolute->m_localAnchorA; - m_localAnchorA = revolute->m_localAnchorB; - m_referenceAngleA = revolute->m_referenceAngle; - m_localAxisC.SetZero(); - - coordinateA = aA - aC - m_referenceAngleA; - } - else - { - b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; - m_localAnchorC = prismatic->m_localAnchorA; - m_localAnchorA = prismatic->m_localAnchorB; - m_referenceAngleA = prismatic->m_referenceAngle; - m_localAxisC = prismatic->m_localXAxisA; - - b2Vec2 pC = m_localAnchorC; - b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); - coordinateA = b2Dot(pA - pC, m_localAxisC); - } - - m_bodyD = m_joint2->GetBodyA(); - m_bodyB = m_joint2->GetBodyB(); - - // Get geometry of joint2 - b2Transform xfB = m_bodyB->m_xf; - float32 aB = m_bodyB->m_sweep.a; - b2Transform xfD = m_bodyD->m_xf; - float32 aD = m_bodyD->m_sweep.a; - - if (m_typeB == e_revoluteJoint) - { - b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; - m_localAnchorD = revolute->m_localAnchorA; - m_localAnchorB = revolute->m_localAnchorB; - m_referenceAngleB = revolute->m_referenceAngle; - m_localAxisD.SetZero(); - - coordinateB = aB - aD - m_referenceAngleB; - } - else - { - b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; - m_localAnchorD = prismatic->m_localAnchorA; - m_localAnchorB = prismatic->m_localAnchorB; - m_referenceAngleB = prismatic->m_referenceAngle; - m_localAxisD = prismatic->m_localXAxisA; - - b2Vec2 pD = m_localAnchorD; - b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); - coordinateB = b2Dot(pB - pD, m_localAxisD); - } - - m_ratio = def->ratio; - - m_constant = coordinateA + m_ratio * coordinateB; - - m_impulse = 0.0f; -} - -void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_indexC = m_bodyC->m_islandIndex; - m_indexD = m_bodyD->m_islandIndex; - m_lcA = m_bodyA->m_sweep.localCenter; - m_lcB = m_bodyB->m_sweep.localCenter; - m_lcC = m_bodyC->m_sweep.localCenter; - m_lcD = m_bodyD->m_sweep.localCenter; - m_mA = m_bodyA->m_invMass; - m_mB = m_bodyB->m_invMass; - m_mC = m_bodyC->m_invMass; - m_mD = m_bodyD->m_invMass; - m_iA = m_bodyA->m_invI; - m_iB = m_bodyB->m_invI; - m_iC = m_bodyC->m_invI; - m_iD = m_bodyD->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Vec2 cC = data.positions[m_indexC].c; - float32 aC = data.positions[m_indexC].a; - b2Vec2 vC = data.velocities[m_indexC].v; - float32 wC = data.velocities[m_indexC].w; - - b2Vec2 cD = data.positions[m_indexD].c; - float32 aD = data.positions[m_indexD].a; - b2Vec2 vD = data.velocities[m_indexD].v; - float32 wD = data.velocities[m_indexD].w; - - b2Rot qA(aA), qB(aB), qC(aC), qD(aD); - - m_mass = 0.0f; - - if (m_typeA == e_revoluteJoint) - { - m_JvAC.SetZero(); - m_JwA = 1.0f; - m_JwC = 1.0f; - m_mass += m_iA + m_iC; - } - else - { - b2Vec2 u = b2Mul(qC, m_localAxisC); - b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); - m_JvAC = u; - m_JwC = b2Cross(rC, u); - m_JwA = b2Cross(rA, u); - m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; - } - - if (m_typeB == e_revoluteJoint) - { - m_JvBD.SetZero(); - m_JwB = m_ratio; - m_JwD = m_ratio; - m_mass += m_ratio * m_ratio * (m_iB + m_iD); - } - else - { - b2Vec2 u = b2Mul(qD, m_localAxisD); - b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); - m_JvBD = m_ratio * u; - m_JwD = m_ratio * b2Cross(rD, u); - m_JwB = m_ratio * b2Cross(rB, u); - m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; - } - - // Compute effective mass. - m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; - - if (data.step.warmStarting) - { - vA += (m_mA * m_impulse) * m_JvAC; - wA += m_iA * m_impulse * m_JwA; - vB += (m_mB * m_impulse) * m_JvBD; - wB += m_iB * m_impulse * m_JwB; - vC -= (m_mC * m_impulse) * m_JvAC; - wC -= m_iC * m_impulse * m_JwC; - vD -= (m_mD * m_impulse) * m_JvBD; - wD -= m_iD * m_impulse * m_JwD; - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; - data.velocities[m_indexC].v = vC; - data.velocities[m_indexC].w = wC; - data.velocities[m_indexD].v = vD; - data.velocities[m_indexD].w = wD; -} - -void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - b2Vec2 vC = data.velocities[m_indexC].v; - float32 wC = data.velocities[m_indexC].w; - b2Vec2 vD = data.velocities[m_indexD].v; - float32 wD = data.velocities[m_indexD].w; - - float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); - Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); - - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - vA += (m_mA * impulse) * m_JvAC; - wA += m_iA * impulse * m_JwA; - vB += (m_mB * impulse) * m_JvBD; - wB += m_iB * impulse * m_JwB; - vC -= (m_mC * impulse) * m_JvAC; - wC -= m_iC * impulse * m_JwC; - vD -= (m_mD * impulse) * m_JvBD; - wD -= m_iD * impulse * m_JwD; - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; - data.velocities[m_indexC].v = vC; - data.velocities[m_indexC].w = wC; - data.velocities[m_indexD].v = vD; - data.velocities[m_indexD].w = wD; -} - -bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 cC = data.positions[m_indexC].c; - float32 aC = data.positions[m_indexC].a; - b2Vec2 cD = data.positions[m_indexD].c; - float32 aD = data.positions[m_indexD].a; - - b2Rot qA(aA), qB(aB), qC(aC), qD(aD); - - float32 linearError = 0.0f; - - float32 coordinateA, coordinateB; - - b2Vec2 JvAC, JvBD; - float32 JwA, JwB, JwC, JwD; - float32 mass = 0.0f; - - if (m_typeA == e_revoluteJoint) - { - JvAC.SetZero(); - JwA = 1.0f; - JwC = 1.0f; - mass += m_iA + m_iC; - - coordinateA = aA - aC - m_referenceAngleA; - } - else - { - b2Vec2 u = b2Mul(qC, m_localAxisC); - b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); - JvAC = u; - JwC = b2Cross(rC, u); - JwA = b2Cross(rA, u); - mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; - - b2Vec2 pC = m_localAnchorC - m_lcC; - b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); - coordinateA = b2Dot(pA - pC, m_localAxisC); - } - - if (m_typeB == e_revoluteJoint) - { - JvBD.SetZero(); - JwB = m_ratio; - JwD = m_ratio; - mass += m_ratio * m_ratio * (m_iB + m_iD); - - coordinateB = aB - aD - m_referenceAngleB; - } - else - { - b2Vec2 u = b2Mul(qD, m_localAxisD); - b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); - JvBD = m_ratio * u; - JwD = m_ratio * b2Cross(rD, u); - JwB = m_ratio * b2Cross(rB, u); - mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; - - b2Vec2 pD = m_localAnchorD - m_lcD; - b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); - coordinateB = b2Dot(pB - pD, m_localAxisD); - } - - float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; - - float32 impulse = 0.0f; - if (mass > 0.0f) - { - impulse = -C / mass; - } - - cA += m_mA * impulse * JvAC; - aA += m_iA * impulse * JwA; - cB += m_mB * impulse * JvBD; - aB += m_iB * impulse * JwB; - cC -= m_mC * impulse * JvAC; - aC -= m_iC * impulse * JwC; - cD -= m_mD * impulse * JvBD; - aD -= m_iD * impulse * JwD; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - data.positions[m_indexC].c = cC; - data.positions[m_indexC].a = aC; - data.positions[m_indexD].c = cD; - data.positions[m_indexD].a = aD; - - // TODO_ERIN not implemented - return linearError < b2_linearSlop; -} - -b2Vec2 b2GearJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2GearJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P = m_impulse * m_JvAC; - return inv_dt * P; -} - -float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const -{ - float32 L = m_impulse * m_JwA; - return inv_dt * L; -} - -void b2GearJoint::SetRatio(float32 ratio) -{ - b2Assert(b2IsValid(ratio)); - m_ratio = ratio; -} - -float32 b2GearJoint::GetRatio() const -{ - return m_ratio; -} - -void b2GearJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - int32 index1 = m_joint1->m_index; - int32 index2 = m_joint2->m_index; - - b2Log(" b2GearJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.joint1 = joints[%d];\n", index1); - b2Log(" jd.joint2 = joints[%d];\n", index2); - b2Log(" jd.ratio = %.15lef;\n", m_ratio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2GearJoint.h b/external/box2d/Dynamics/Joints/b2GearJoint.h deleted file mode 100644 index f926bf6ef1..0000000000 --- a/external/box2d/Dynamics/Joints/b2GearJoint.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_GEAR_JOINT_H -#define B2_GEAR_JOINT_H - -#include - -/// Gear joint definition. This definition requires two existing -/// revolute or prismatic joints (any combination will work). -struct b2GearJointDef : public b2JointDef -{ - b2GearJointDef() - { - type = e_gearJoint; - joint1 = NULL; - joint2 = NULL; - ratio = 1.0f; - } - - /// The first revolute/prismatic joint attached to the gear joint. - b2Joint* joint1; - - /// The second revolute/prismatic joint attached to the gear joint. - b2Joint* joint2; - - /// The gear ratio. - /// @see b2GearJoint for explanation. - float32 ratio; -}; - -/// A gear joint is used to connect two joints together. Either joint -/// can be a revolute or prismatic joint. You specify a gear ratio -/// to bind the motions together: -/// coordinate1 + ratio * coordinate2 = constant -/// The ratio can be negative or positive. If one joint is a revolute joint -/// and the other joint is a prismatic joint, then the ratio will have units -/// of length or units of 1/length. -/// @warning You have to manually destroy the gear joint if joint1 or joint2 -/// is destroyed. -class b2GearJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the first joint. - b2Joint* GetJoint1() { return m_joint1; } - - /// Get the second joint. - b2Joint* GetJoint2() { return m_joint2; } - - /// Set/Get the gear ratio. - void SetRatio(float32 ratio); - float32 GetRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2GearJoint(const b2GearJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Joint* m_joint1; - b2Joint* m_joint2; - - b2JointType m_typeA; - b2JointType m_typeB; - - // Body A is connected to body C - // Body B is connected to body D - b2Body* m_bodyC; - b2Body* m_bodyD; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localAnchorC; - b2Vec2 m_localAnchorD; - - b2Vec2 m_localAxisC; - b2Vec2 m_localAxisD; - - float32 m_referenceAngleA; - float32 m_referenceAngleB; - - float32 m_constant; - float32 m_ratio; - - float32 m_impulse; - - // Solver temp - int32 m_indexA, m_indexB, m_indexC, m_indexD; - b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; - float32 m_mA, m_mB, m_mC, m_mD; - float32 m_iA, m_iB, m_iC, m_iD; - b2Vec2 m_JvAC, m_JvBD; - float32 m_JwA, m_JwB, m_JwC, m_JwD; - float32 m_mass; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2Joint.cpp b/external/box2d/Dynamics/Joints/b2Joint.cpp deleted file mode 100644 index 6853b09f0b..0000000000 --- a/external/box2d/Dynamics/Joints/b2Joint.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) -{ - b2Joint* joint = NULL; - - switch (def->type) - { - case e_distanceJoint: - { - void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); - joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); - } - break; - - case e_mouseJoint: - { - void* mem = allocator->Allocate(sizeof(b2MouseJoint)); - joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); - } - break; - - case e_prismaticJoint: - { - void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); - joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); - } - break; - - case e_revoluteJoint: - { - void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); - joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); - } - break; - - case e_pulleyJoint: - { - void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); - joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); - } - break; - - case e_gearJoint: - { - void* mem = allocator->Allocate(sizeof(b2GearJoint)); - joint = new (mem) b2GearJoint((b2GearJointDef*)def); - } - break; - - case e_wheelJoint: - { - void* mem = allocator->Allocate(sizeof(b2WheelJoint)); - joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); - } - break; - - case e_weldJoint: - { - void* mem = allocator->Allocate(sizeof(b2WeldJoint)); - joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); - } - break; - - case e_frictionJoint: - { - void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); - joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); - } - break; - - case e_ropeJoint: - { - void* mem = allocator->Allocate(sizeof(b2RopeJoint)); - joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); - } - break; - - default: - b2Assert(false); - break; - } - - return joint; -} - -void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) -{ - joint->~b2Joint(); - switch (joint->m_type) - { - case e_distanceJoint: - allocator->Free(joint, sizeof(b2DistanceJoint)); - break; - - case e_mouseJoint: - allocator->Free(joint, sizeof(b2MouseJoint)); - break; - - case e_prismaticJoint: - allocator->Free(joint, sizeof(b2PrismaticJoint)); - break; - - case e_revoluteJoint: - allocator->Free(joint, sizeof(b2RevoluteJoint)); - break; - - case e_pulleyJoint: - allocator->Free(joint, sizeof(b2PulleyJoint)); - break; - - case e_gearJoint: - allocator->Free(joint, sizeof(b2GearJoint)); - break; - - case e_wheelJoint: - allocator->Free(joint, sizeof(b2WheelJoint)); - break; - - case e_weldJoint: - allocator->Free(joint, sizeof(b2WeldJoint)); - break; - - case e_frictionJoint: - allocator->Free(joint, sizeof(b2FrictionJoint)); - break; - - case e_ropeJoint: - allocator->Free(joint, sizeof(b2RopeJoint)); - break; - - default: - b2Assert(false); - break; - } -} - -b2Joint::b2Joint(const b2JointDef* def) -{ - b2Assert(def->bodyA != def->bodyB); - - m_type = def->type; - m_prev = NULL; - m_next = NULL; - m_bodyA = def->bodyA; - m_bodyB = def->bodyB; - m_index = 0; - m_collideConnected = def->collideConnected; - m_islandFlag = false; - m_userData = def->userData; - - m_edgeA.joint = NULL; - m_edgeA.other = NULL; - m_edgeA.prev = NULL; - m_edgeA.next = NULL; - - m_edgeB.joint = NULL; - m_edgeB.other = NULL; - m_edgeB.prev = NULL; - m_edgeB.next = NULL; -} - -bool b2Joint::IsActive() const -{ - return m_bodyA->IsActive() && m_bodyB->IsActive(); -} diff --git a/external/box2d/Dynamics/Joints/b2Joint.h b/external/box2d/Dynamics/Joints/b2Joint.h deleted file mode 100644 index b4ea576665..0000000000 --- a/external/box2d/Dynamics/Joints/b2Joint.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_JOINT_H -#define B2_JOINT_H - -#include - -class b2Body; -class b2Joint; -struct b2SolverData; -class b2BlockAllocator; - -enum b2JointType -{ - e_unknownJoint, - e_revoluteJoint, - e_prismaticJoint, - e_distanceJoint, - e_pulleyJoint, - e_mouseJoint, - e_gearJoint, - e_wheelJoint, - e_weldJoint, - e_frictionJoint, - e_ropeJoint -}; - -enum b2LimitState -{ - e_inactiveLimit, - e_atLowerLimit, - e_atUpperLimit, - e_equalLimits -}; - -struct b2Jacobian -{ - b2Vec2 linear; - float32 angularA; - float32 angularB; -}; - -/// A joint edge is used to connect bodies and joints together -/// in a joint graph where each body is a node and each joint -/// is an edge. A joint edge belongs to a doubly linked list -/// maintained in each attached body. Each joint has two joint -/// nodes, one for each attached body. -struct b2JointEdge -{ - b2Body* other; ///< provides quick access to the other body attached. - b2Joint* joint; ///< the joint - b2JointEdge* prev; ///< the previous joint edge in the body's joint list - b2JointEdge* next; ///< the next joint edge in the body's joint list -}; - -/// Joint definitions are used to construct joints. -struct b2JointDef -{ - b2JointDef() - { - type = e_unknownJoint; - userData = NULL; - bodyA = NULL; - bodyB = NULL; - collideConnected = false; - } - - /// The joint type is set automatically for concrete joint types. - b2JointType type; - - /// Use this to attach application specific data to your joints. - void* userData; - - /// The first attached body. - b2Body* bodyA; - - /// The second attached body. - b2Body* bodyB; - - /// Set this flag to true if the attached bodies should collide. - bool collideConnected; -}; - -/// The base joint class. Joints are used to constraint two bodies together in -/// various fashions. Some joints also feature limits and motors. -class b2Joint -{ -public: - - /// Get the type of the concrete joint. - b2JointType GetType() const; - - /// Get the first body attached to this joint. - b2Body* GetBodyA(); - - /// Get the second body attached to this joint. - b2Body* GetBodyB(); - - /// Get the anchor point on bodyA in world coordinates. - virtual b2Vec2 GetAnchorA() const = 0; - - /// Get the anchor point on bodyB in world coordinates. - virtual b2Vec2 GetAnchorB() const = 0; - - /// Get the reaction force on bodyB at the joint anchor in Newtons. - virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; - - /// Get the reaction torque on bodyB in N*m. - virtual float32 GetReactionTorque(float32 inv_dt) const = 0; - - /// Get the next joint the world joint list. - b2Joint* GetNext(); - const b2Joint* GetNext() const; - - /// Get the user data pointer. - void* GetUserData() const; - - /// Set the user data pointer. - void SetUserData(void* data); - - /// Short-cut function to determine if either body is inactive. - bool IsActive() const; - - /// Get collide connected. - /// Note: modifying the collide connect flag won't work correctly because - /// the flag is only checked when fixture AABBs begin to overlap. - bool GetCollideConnected() const; - - /// Dump this joint to the log file. - virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } - -protected: - friend class b2World; - friend class b2Body; - friend class b2Island; - friend class b2GearJoint; - - static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); - static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); - - b2Joint(const b2JointDef* def); - virtual ~b2Joint() {} - - virtual void InitVelocityConstraints(const b2SolverData& data) = 0; - virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; - - // This returns true if the position errors are within tolerance. - virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; - - b2JointType m_type; - b2Joint* m_prev; - b2Joint* m_next; - b2JointEdge m_edgeA; - b2JointEdge m_edgeB; - b2Body* m_bodyA; - b2Body* m_bodyB; - - int32 m_index; - - bool m_islandFlag; - bool m_collideConnected; - - void* m_userData; -}; - -inline b2JointType b2Joint::GetType() const -{ - return m_type; -} - -inline b2Body* b2Joint::GetBodyA() -{ - return m_bodyA; -} - -inline b2Body* b2Joint::GetBodyB() -{ - return m_bodyB; -} - -inline b2Joint* b2Joint::GetNext() -{ - return m_next; -} - -inline const b2Joint* b2Joint::GetNext() const -{ - return m_next; -} - -inline void* b2Joint::GetUserData() const -{ - return m_userData; -} - -inline void b2Joint::SetUserData(void* data) -{ - m_userData = data; -} - -inline bool b2Joint::GetCollideConnected() const -{ - return m_collideConnected; -} - -#endif diff --git a/external/box2d/Dynamics/Joints/b2MouseJoint.cpp b/external/box2d/Dynamics/Joints/b2MouseJoint.cpp deleted file mode 100644 index 237d9d519a..0000000000 --- a/external/box2d/Dynamics/Joints/b2MouseJoint.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include - -// p = attached point, m = mouse point -// C = p - m -// Cdot = v -// = v + cross(w, r) -// J = [I r_skew] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) -: b2Joint(def) -{ - b2Assert(def->target.IsValid()); - b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); - b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); - b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); - - m_targetA = def->target; - m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); - - m_maxForce = def->maxForce; - m_impulse.SetZero(); - - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_beta = 0.0f; - m_gamma = 0.0f; -} - -void b2MouseJoint::SetTarget(const b2Vec2& target) -{ - if (m_bodyB->IsAwake() == false) - { - m_bodyB->SetAwake(true); - } - m_targetA = target; -} - -const b2Vec2& b2MouseJoint::GetTarget() const -{ - return m_targetA; -} - -void b2MouseJoint::SetMaxForce(float32 force) -{ - m_maxForce = force; -} - -float32 b2MouseJoint::GetMaxForce() const -{ - return m_maxForce; -} - -void b2MouseJoint::SetFrequency(float32 hz) -{ - m_frequencyHz = hz; -} - -float32 b2MouseJoint::GetFrequency() const -{ - return m_frequencyHz; -} - -void b2MouseJoint::SetDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -float32 b2MouseJoint::GetDampingRatio() const -{ - return m_dampingRatio; -} - -void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexB = m_bodyB->m_islandIndex; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassB = m_bodyB->m_invMass; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qB(aB); - - float32 mass = m_bodyB->GetMass(); - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * mass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = mass * (omega * omega); - - // magic formulas - // gamma has units of inverse mass. - // beta has units of inverse time. - float32 h = data.step.dt; - b2Assert(d + h * k > b2_epsilon); - m_gamma = h * (d + h * k); - if (m_gamma != 0.0f) - { - m_gamma = 1.0f / m_gamma; - } - m_beta = h * k * m_gamma; - - // Compute the effective mass matrix. - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] - // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] - // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] - b2Mat22 K; - K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; - K.ex.y = -m_invIB * m_rB.x * m_rB.y; - K.ey.x = K.ex.y; - K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; - - m_mass = K.GetInverse(); - - m_C = cB + m_rB - m_targetA; - m_C *= m_beta; - - // Cheat with some damping - wB *= 0.98f; - - if (data.step.warmStarting) - { - m_impulse *= data.step.dtRatio; - vB += m_invMassB * m_impulse; - wB += m_invIB * b2Cross(m_rB, m_impulse); - } - else - { - m_impulse.SetZero(); - } - - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = v + cross(w, r) - b2Vec2 Cdot = vB + b2Cross(wB, m_rB); - b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); - - b2Vec2 oldImpulse = m_impulse; - m_impulse += impulse; - float32 maxImpulse = data.step.dt * m_maxForce; - if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) - { - m_impulse *= maxImpulse / m_impulse.Length(); - } - impulse = m_impulse - oldImpulse; - - vB += m_invMassB * impulse; - wB += m_invIB * b2Cross(m_rB, impulse); - - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) -{ - B2_NOT_USED(data); - return true; -} - -b2Vec2 b2MouseJoint::GetAnchorA() const -{ - return m_targetA; -} - -b2Vec2 b2MouseJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * m_impulse; -} - -float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * 0.0f; -} diff --git a/external/box2d/Dynamics/Joints/b2MouseJoint.h b/external/box2d/Dynamics/Joints/b2MouseJoint.h deleted file mode 100644 index 1bbc194f4c..0000000000 --- a/external/box2d/Dynamics/Joints/b2MouseJoint.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -* Copyright (c) 2006-2007 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. -*/ - -#ifndef B2_MOUSE_JOINT_H -#define B2_MOUSE_JOINT_H - -#include - -/// Mouse joint definition. This requires a world target point, -/// tuning parameters, and the time step. -struct b2MouseJointDef : public b2JointDef -{ - b2MouseJointDef() - { - type = e_mouseJoint; - target.Set(0.0f, 0.0f); - maxForce = 0.0f; - frequencyHz = 5.0f; - dampingRatio = 0.7f; - } - - /// The initial world target point. This is assumed - /// to coincide with the body anchor initially. - b2Vec2 target; - - /// The maximum constraint force that can be exerted - /// to move the candidate body. Usually you will express - /// as some multiple of the weight (multiplier * mass * gravity). - float32 maxForce; - - /// The response speed. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A mouse joint is used to make a point on a body track a -/// specified world point. This a soft constraint with a maximum -/// force. This allows the constraint to stretch and without -/// applying huge forces. -/// NOTE: this joint is not documented in the manual because it was -/// developed to be used in the testbed. If you want to learn how to -/// use the mouse joint, look at the testbed. -class b2MouseJoint : public b2Joint -{ -public: - - /// Implements b2Joint. - b2Vec2 GetAnchorA() const; - - /// Implements b2Joint. - b2Vec2 GetAnchorB() const; - - /// Implements b2Joint. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Implements b2Joint. - float32 GetReactionTorque(float32 inv_dt) const; - - /// Use this to update the target point. - void SetTarget(const b2Vec2& target); - const b2Vec2& GetTarget() const; - - /// Set/get the maximum force in Newtons. - void SetMaxForce(float32 force); - float32 GetMaxForce() const; - - /// Set/get the frequency in Hertz. - void SetFrequency(float32 hz); - float32 GetFrequency() const; - - /// Set/get the damping ratio (dimensionless). - void SetDampingRatio(float32 ratio); - float32 GetDampingRatio() const; - - /// The mouse joint does not support dumping. - void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } - -protected: - friend class b2Joint; - - b2MouseJoint(const b2MouseJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_localAnchorB; - b2Vec2 m_targetA; - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_beta; - - // Solver shared - b2Vec2 m_impulse; - float32 m_maxForce; - float32 m_gamma; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rB; - b2Vec2 m_localCenterB; - float32 m_invMassB; - float32 m_invIB; - b2Mat22 m_mass; - b2Vec2 m_C; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp b/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp deleted file mode 100644 index 4849f729f5..0000000000 --- a/external/box2d/Dynamics/Joints/b2PrismaticJoint.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Linear constraint (point-to-line) -// d = p2 - p1 = x2 + r2 - x1 - r1 -// C = dot(perp, d) -// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) -// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) -// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] -// -// Angular constraint -// C = a2 - a1 + a_initial -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// -// K = J * invM * JT -// -// J = [-a -s1 a s2] -// [0 -1 0 1] -// a = perp -// s1 = cross(d + r1, a) = cross(p2 - x1, a) -// s2 = cross(r2, a) = cross(p2 - x2, a) - - -// Motor/Limit linear constraint -// C = dot(ax1, d) -// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) -// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] - -// Block Solver -// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even -// when the mass has poor distribution (leading to large torques about the joint anchor points). -// -// The Jacobian has 3 rows: -// J = [-uT -s1 uT s2] // linear -// [0 -1 0 1] // angular -// [-vT -a1 vT a2] // limit -// -// u = perp -// v = axis -// s1 = cross(d + r1, u), s2 = cross(r2, u) -// a1 = cross(d + r1, v), a2 = cross(r2, v) - -// M * (v2 - v1) = JT * df -// J * v2 = bias -// -// v2 = v1 + invM * JT * df -// J * (v1 + invM * JT * df) = bias -// K * df = bias - J * v1 = -Cdot -// K = J * invM * JT -// Cdot = J * v1 - bias -// -// Now solve for f2. -// df = f2 - f1 -// K * (f2 - f1) = -Cdot -// f2 = invK * (-Cdot) + f1 -// -// Clamp accumulated limit impulse. -// lower: f2(3) = max(f2(3), 0) -// upper: f2(3) = min(f2(3), 0) -// -// Solve for correct f2(1:2) -// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 -// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) -// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) -// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) -// -// Now compute impulse to be applied: -// df = f2 - f1 - -void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - localAxisA = bodyA->GetLocalVector(axis); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_localXAxisA = def->localAxisA; - m_localXAxisA.Normalize(); - m_localYAxisA = b2Cross(1.0f, m_localXAxisA); - m_referenceAngle = def->referenceAngle; - - m_impulse.SetZero(); - m_motorMass = 0.0; - m_motorImpulse = 0.0f; - - m_lowerTranslation = def->lowerTranslation; - m_upperTranslation = def->upperTranslation; - m_maxMotorForce = def->maxMotorForce; - m_motorSpeed = def->motorSpeed; - m_enableLimit = def->enableLimit; - m_enableMotor = def->enableMotor; - m_limitState = e_inactiveLimit; - - m_axis.SetZero(); - m_perp.SetZero(); -} - -void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective masses. - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = (cB - cA) + rB - rA; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Compute motor Jacobian and effective mass. - { - m_axis = b2Mul(qA, m_localXAxisA); - m_a1 = b2Cross(d + rA, m_axis); - m_a2 = b2Cross(rB, m_axis); - - m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - } - - // Prismatic constraint. - { - m_perp = b2Mul(qA, m_localYAxisA); - - m_s1 = b2Cross(d + rA, m_perp); - m_s2 = b2Cross(rB, m_perp); - - float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; - float32 k12 = iA * m_s1 + iB * m_s2; - float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - // For bodies with fixed rotation. - k22 = 1.0f; - } - float32 k23 = iA * m_a1 + iB * m_a2; - float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; - - m_K.ex.Set(k11, k12, k13); - m_K.ey.Set(k12, k22, k23); - m_K.ez.Set(k13, k23, k33); - } - - // Compute motor and limit terms. - if (m_enableLimit) - { - float32 jointTranslation = b2Dot(m_axis, d); - if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) - { - m_limitState = e_equalLimits; - } - else if (jointTranslation <= m_lowerTranslation) - { - if (m_limitState != e_atLowerLimit) - { - m_limitState = e_atLowerLimit; - m_impulse.z = 0.0f; - } - } - else if (jointTranslation >= m_upperTranslation) - { - if (m_limitState != e_atUpperLimit) - { - m_limitState = e_atUpperLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - - if (m_enableMotor == false) - { - m_motorImpulse = 0.0f; - } - - if (data.step.warmStarting) - { - // Account for variable time step. - m_impulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; - float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; - float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - else - { - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Solve linear motor constraint. - if (m_enableMotor && m_limitState != e_equalLimits) - { - float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; - float32 impulse = m_motorMass * (m_motorSpeed - Cdot); - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorForce; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - b2Vec2 P = impulse * m_axis; - float32 LA = impulse * m_a1; - float32 LB = impulse * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - b2Vec2 Cdot1; - Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; - Cdot1.y = wB - wA; - - if (m_enableLimit && m_limitState != e_inactiveLimit) - { - // Solve prismatic and limit constraint in block form. - float32 Cdot2; - Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 f1 = m_impulse; - b2Vec3 df = m_K.Solve33(-Cdot); - m_impulse += df; - - if (m_limitState == e_atLowerLimit) - { - m_impulse.z = b2Max(m_impulse.z, 0.0f); - } - else if (m_limitState == e_atUpperLimit) - { - m_impulse.z = b2Min(m_impulse.z, 0.0f); - } - - // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) - b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); - b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); - m_impulse.x = f2r.x; - m_impulse.y = f2r.y; - - df = m_impulse - f1; - - b2Vec2 P = df.x * m_perp + df.z * m_axis; - float32 LA = df.x * m_s1 + df.y + df.z * m_a1; - float32 LB = df.x * m_s2 + df.y + df.z * m_a2; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - else - { - // Limit is inactive, just solve the prismatic constraint in block form. - b2Vec2 df = m_K.Solve22(-Cdot1); - m_impulse.x += df.x; - m_impulse.y += df.y; - - b2Vec2 P = df.x * m_perp; - float32 LA = df.x * m_s1 + df.y; - float32 LB = df.x * m_s2 + df.y; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - - b2Vec2 Cdot10 = Cdot1; - - Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; - Cdot1.y = wB - wA; - - if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f) - { - b2Vec2 test = b2Mul22(m_K, df); - Cdot1.x += 0.0f; - } - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - // Compute fresh Jacobians - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = cB + rB - cA - rA; - - b2Vec2 axis = b2Mul(qA, m_localXAxisA); - float32 a1 = b2Cross(d + rA, axis); - float32 a2 = b2Cross(rB, axis); - b2Vec2 perp = b2Mul(qA, m_localYAxisA); - - float32 s1 = b2Cross(d + rA, perp); - float32 s2 = b2Cross(rB, perp); - - b2Vec3 impulse; - b2Vec2 C1; - C1.x = b2Dot(perp, d); - C1.y = aB - aA - m_referenceAngle; - - float32 linearError = b2Abs(C1.x); - float32 angularError = b2Abs(C1.y); - - bool active = false; - float32 C2 = 0.0f; - if (m_enableLimit) - { - float32 translation = b2Dot(axis, d); - if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) - { - // Prevent large angular corrections - C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); - linearError = b2Max(linearError, b2Abs(translation)); - active = true; - } - else if (translation <= m_lowerTranslation) - { - // Prevent large linear corrections and allow some slop. - C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); - linearError = b2Max(linearError, m_lowerTranslation - translation); - active = true; - } - else if (translation >= m_upperTranslation) - { - // Prevent large linear corrections and allow some slop. - C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); - linearError = b2Max(linearError, translation - m_upperTranslation); - active = true; - } - } - - if (active) - { - float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; - float32 k12 = iA * s1 + iB * s2; - float32 k13 = iA * s1 * a1 + iB * s2 * a2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - // For fixed rotation - k22 = 1.0f; - } - float32 k23 = iA * a1 + iB * a2; - float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; - - b2Mat33 K; - K.ex.Set(k11, k12, k13); - K.ey.Set(k12, k22, k23); - K.ez.Set(k13, k23, k33); - - b2Vec3 C; - C.x = C1.x; - C.y = C1.y; - C.z = C2; - - impulse = K.Solve33(-C); - } - else - { - float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; - float32 k12 = iA * s1 + iB * s2; - float32 k22 = iA + iB; - if (k22 == 0.0f) - { - k22 = 1.0f; - } - - b2Mat22 K; - K.ex.Set(k11, k12); - K.ey.Set(k12, k22); - - b2Vec2 impulse1 = K.Solve(-C1); - impulse.x = impulse1.x; - impulse.y = impulse1.y; - impulse.z = 0.0f; - } - - b2Vec2 P = impulse.x * perp + impulse.z * axis; - float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; - float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; - - cA -= mA * P; - aA -= iA * LA; - cB += mB * P; - aB += iB * LB; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return linearError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2PrismaticJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2PrismaticJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); -} - -float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.y; -} - -float32 b2PrismaticJoint::GetJointTranslation() const -{ - b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); - b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); - b2Vec2 d = pB - pA; - b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); - - float32 translation = b2Dot(d, axis); - return translation; -} - -float32 b2PrismaticJoint::GetJointSpeed() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - - b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); - b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); - b2Vec2 p1 = bA->m_sweep.c + rA; - b2Vec2 p2 = bB->m_sweep.c + rB; - b2Vec2 d = p2 - p1; - b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); - - b2Vec2 vA = bA->m_linearVelocity; - b2Vec2 vB = bB->m_linearVelocity; - float32 wA = bA->m_angularVelocity; - float32 wB = bB->m_angularVelocity; - - float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); - return speed; -} - -bool b2PrismaticJoint::IsLimitEnabled() const -{ - return m_enableLimit; -} - -void b2PrismaticJoint::EnableLimit(bool flag) -{ - if (flag != m_enableLimit) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableLimit = flag; - m_impulse.z = 0.0f; - } -} - -float32 b2PrismaticJoint::GetLowerLimit() const -{ - return m_lowerTranslation; -} - -float32 b2PrismaticJoint::GetUpperLimit() const -{ - return m_upperTranslation; -} - -void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) -{ - b2Assert(lower <= upper); - if (lower != m_lowerTranslation || upper != m_upperTranslation) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_lowerTranslation = lower; - m_upperTranslation = upper; - m_impulse.z = 0.0f; - } -} - -bool b2PrismaticJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2PrismaticJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -void b2PrismaticJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2PrismaticJoint::SetMaxMotorForce(float32 force) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorForce = force; -} - -float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2PrismaticJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2PrismaticJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); - b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); - b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2PrismaticJoint.h b/external/box2d/Dynamics/Joints/b2PrismaticJoint.h deleted file mode 100644 index aca2859b45..0000000000 --- a/external/box2d/Dynamics/Joints/b2PrismaticJoint.h +++ /dev/null @@ -1,196 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_PRISMATIC_JOINT_H -#define B2_PRISMATIC_JOINT_H - -#include - -/// Prismatic joint definition. This requires defining a line of -/// motion using an axis and an anchor point. The definition uses local -/// anchor points and a local axis so that the initial configuration -/// can violate the constraint slightly. The joint translation is zero -/// when the local anchor points coincide in world space. Using local -/// anchors and a local axis helps when saving and loading a game. -struct b2PrismaticJointDef : public b2JointDef -{ - b2PrismaticJointDef() - { - type = e_prismaticJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - localAxisA.Set(1.0f, 0.0f); - referenceAngle = 0.0f; - enableLimit = false; - lowerTranslation = 0.0f; - upperTranslation = 0.0f; - enableMotor = false; - maxMotorForce = 0.0f; - motorSpeed = 0.0f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and unit world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The local translation unit axis in bodyA. - b2Vec2 localAxisA; - - /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. - float32 referenceAngle; - - /// Enable/disable the joint limit. - bool enableLimit; - - /// The lower translation limit, usually in meters. - float32 lowerTranslation; - - /// The upper translation limit, usually in meters. - float32 upperTranslation; - - /// Enable/disable the joint motor. - bool enableMotor; - - /// The maximum motor torque, usually in N-m. - float32 maxMotorForce; - - /// The desired motor speed in radians per second. - float32 motorSpeed; -}; - -/// A prismatic joint. This joint provides one degree of freedom: translation -/// along an axis fixed in bodyA. Relative rotation is prevented. You can -/// use a joint limit to restrict the range of motion and a joint motor to -/// drive the motion or to model joint friction. -class b2PrismaticJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// The local joint axis relative to bodyA. - const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Get the current joint translation, usually in meters. - float32 GetJointTranslation() const; - - /// Get the current joint translation speed, usually in meters per second. - float32 GetJointSpeed() const; - - /// Is the joint limit enabled? - bool IsLimitEnabled() const; - - /// Enable/disable the joint limit. - void EnableLimit(bool flag); - - /// Get the lower joint limit, usually in meters. - float32 GetLowerLimit() const; - - /// Get the upper joint limit, usually in meters. - float32 GetUpperLimit() const; - - /// Set the joint limits, usually in meters. - void SetLimits(float32 lower, float32 upper); - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed, usually in meters per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed, usually in meters per second. - float32 GetMotorSpeed() const; - - /// Set the maximum motor force, usually in N. - void SetMaxMotorForce(float32 force); - float32 GetMaxMotorForce() const { return m_maxMotorForce; } - - /// Get the current motor force given the inverse time step, usually in N. - float32 GetMotorForce(float32 inv_dt) const; - - /// Dump to b2Log - void Dump(); - -protected: - friend class b2Joint; - friend class b2GearJoint; - b2PrismaticJoint(const b2PrismaticJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localXAxisA; - b2Vec2 m_localYAxisA; - float32 m_referenceAngle; - b2Vec3 m_impulse; - float32 m_motorImpulse; - float32 m_lowerTranslation; - float32 m_upperTranslation; - float32 m_maxMotorForce; - float32 m_motorSpeed; - bool m_enableLimit; - bool m_enableMotor; - b2LimitState m_limitState; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Vec2 m_axis, m_perp; - float32 m_s1, m_s2; - float32 m_a1, m_a2; - b2Mat33 m_K; - float32 m_motorMass; -}; - -inline float32 b2PrismaticJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -#endif diff --git a/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp b/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp deleted file mode 100644 index da30fae222..0000000000 --- a/external/box2d/Dynamics/Joints/b2PulleyJoint.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -* Copyright (c) 2007 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 -#include -#include - -// Pulley: -// length1 = norm(p1 - s1) -// length2 = norm(p2 - s2) -// C0 = (length1 + ratio * length2)_initial -// C = C0 - (length1 + ratio * length2) -// u1 = (p1 - s1) / norm(p1 - s1) -// u2 = (p2 - s2) / norm(p2 - s2) -// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) -// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] -// K = J * invM * JT -// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) - -void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, - const b2Vec2& groundA, const b2Vec2& groundB, - const b2Vec2& anchorA, const b2Vec2& anchorB, - float32 r) -{ - bodyA = bA; - bodyB = bB; - groundAnchorA = groundA; - groundAnchorB = groundB; - localAnchorA = bodyA->GetLocalPoint(anchorA); - localAnchorB = bodyB->GetLocalPoint(anchorB); - b2Vec2 dA = anchorA - groundA; - lengthA = dA.Length(); - b2Vec2 dB = anchorB - groundB; - lengthB = dB.Length(); - ratio = r; - b2Assert(ratio > b2_epsilon); -} - -b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) -: b2Joint(def) -{ - m_groundAnchorA = def->groundAnchorA; - m_groundAnchorB = def->groundAnchorB; - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_lengthA = def->lengthA; - m_lengthB = def->lengthB; - - b2Assert(def->ratio != 0.0f); - m_ratio = def->ratio; - - m_constant = def->lengthA + m_ratio * def->lengthB; - - m_impulse = 0.0f; -} - -void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // Get the pulley axes. - m_uA = cA + m_rA - m_groundAnchorA; - m_uB = cB + m_rB - m_groundAnchorB; - - float32 lengthA = m_uA.Length(); - float32 lengthB = m_uB.Length(); - - if (lengthA > 10.0f * b2_linearSlop) - { - m_uA *= 1.0f / lengthA; - } - else - { - m_uA.SetZero(); - } - - if (lengthB > 10.0f * b2_linearSlop) - { - m_uB *= 1.0f / lengthB; - } - else - { - m_uB.SetZero(); - } - - // Compute effective mass. - float32 ruA = b2Cross(m_rA, m_uA); - float32 ruB = b2Cross(m_rB, m_uB); - - float32 mA = m_invMassA + m_invIA * ruA * ruA; - float32 mB = m_invMassB + m_invIB * ruB * ruB; - - m_mass = mA + m_ratio * m_ratio * mB; - - if (m_mass > 0.0f) - { - m_mass = 1.0f / m_mass; - } - - if (data.step.warmStarting) - { - // Scale impulses to support variable time steps. - m_impulse *= data.step.dtRatio; - - // Warm starting. - b2Vec2 PA = -(m_impulse) * m_uA; - b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; - - vA += m_invMassA * PA; - wA += m_invIA * b2Cross(m_rA, PA); - vB += m_invMassB * PB; - wB += m_invIB * b2Cross(m_rB, PB); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - - float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - b2Vec2 PA = -impulse * m_uA; - b2Vec2 PB = -m_ratio * impulse * m_uB; - vA += m_invMassA * PA; - wA += m_invIA * b2Cross(m_rA, PA); - vB += m_invMassB * PB; - wB += m_invIB * b2Cross(m_rB, PB); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // Get the pulley axes. - b2Vec2 uA = cA + rA - m_groundAnchorA; - b2Vec2 uB = cB + rB - m_groundAnchorB; - - float32 lengthA = uA.Length(); - float32 lengthB = uB.Length(); - - if (lengthA > 10.0f * b2_linearSlop) - { - uA *= 1.0f / lengthA; - } - else - { - uA.SetZero(); - } - - if (lengthB > 10.0f * b2_linearSlop) - { - uB *= 1.0f / lengthB; - } - else - { - uB.SetZero(); - } - - // Compute effective mass. - float32 ruA = b2Cross(rA, uA); - float32 ruB = b2Cross(rB, uB); - - float32 mA = m_invMassA + m_invIA * ruA * ruA; - float32 mB = m_invMassB + m_invIB * ruB * ruB; - - float32 mass = mA + m_ratio * m_ratio * mB; - - if (mass > 0.0f) - { - mass = 1.0f / mass; - } - - float32 C = m_constant - lengthA - m_ratio * lengthB; - float32 linearError = b2Abs(C); - - float32 impulse = -mass * C; - - b2Vec2 PA = -impulse * uA; - b2Vec2 PB = -m_ratio * impulse * uB; - - cA += m_invMassA * PA; - aA += m_invIA * b2Cross(rA, PA); - cB += m_invMassB * PB; - aB += m_invIB * b2Cross(rB, PB); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return linearError < b2_linearSlop; -} - -b2Vec2 b2PulleyJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2PulleyJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P = m_impulse * m_uB; - return inv_dt * P; -} - -float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -b2Vec2 b2PulleyJoint::GetGroundAnchorA() const -{ - return m_groundAnchorA; -} - -b2Vec2 b2PulleyJoint::GetGroundAnchorB() const -{ - return m_groundAnchorB; -} - -float32 b2PulleyJoint::GetLengthA() const -{ - b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); - b2Vec2 s = m_groundAnchorA; - b2Vec2 d = p - s; - return d.Length(); -} - -float32 b2PulleyJoint::GetLengthB() const -{ - b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); - b2Vec2 s = m_groundAnchorB; - b2Vec2 d = p - s; - return d.Length(); -} - -float32 b2PulleyJoint::GetRatio() const -{ - return m_ratio; -} - -void b2PulleyJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2PulleyJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); - b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); - b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); - b2Log(" jd.ratio = %.15lef;\n", m_ratio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2PulleyJoint.h b/external/box2d/Dynamics/Joints/b2PulleyJoint.h deleted file mode 100644 index 2f6df4395c..0000000000 --- a/external/box2d/Dynamics/Joints/b2PulleyJoint.h +++ /dev/null @@ -1,143 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_PULLEY_JOINT_H -#define B2_PULLEY_JOINT_H - -#include - -const float32 b2_minPulleyLength = 2.0f; - -/// Pulley joint definition. This requires two ground anchors, -/// two dynamic body anchor points, and a pulley ratio. -struct b2PulleyJointDef : public b2JointDef -{ - b2PulleyJointDef() - { - type = e_pulleyJoint; - groundAnchorA.Set(-1.0f, 1.0f); - groundAnchorB.Set(1.0f, 1.0f); - localAnchorA.Set(-1.0f, 0.0f); - localAnchorB.Set(1.0f, 0.0f); - lengthA = 0.0f; - lengthB = 0.0f; - ratio = 1.0f; - collideConnected = true; - } - - /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. - void Initialize(b2Body* bodyA, b2Body* bodyB, - const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, - const b2Vec2& anchorA, const b2Vec2& anchorB, - float32 ratio); - - /// The first ground anchor in world coordinates. This point never moves. - b2Vec2 groundAnchorA; - - /// The second ground anchor in world coordinates. This point never moves. - b2Vec2 groundAnchorB; - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The a reference length for the segment attached to bodyA. - float32 lengthA; - - /// The a reference length for the segment attached to bodyB. - float32 lengthB; - - /// The pulley ratio, used to simulate a block-and-tackle. - float32 ratio; -}; - -/// The pulley joint is connected to two bodies and two fixed ground points. -/// The pulley supports a ratio such that: -/// length1 + ratio * length2 <= constant -/// Yes, the force transmitted is scaled by the ratio. -/// Warning: the pulley joint can get a bit squirrelly by itself. They often -/// work better when combined with prismatic joints. You should also cover the -/// the anchor points with static shapes to prevent one side from going to -/// zero length. -class b2PulleyJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the first ground anchor. - b2Vec2 GetGroundAnchorA() const; - - /// Get the second ground anchor. - b2Vec2 GetGroundAnchorB() const; - - /// Get the current length of the segment attached to bodyA. - float32 GetLengthA() const; - - /// Get the current length of the segment attached to bodyB. - float32 GetLengthB() const; - - /// Get the pulley ratio. - float32 GetRatio() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2PulleyJoint(const b2PulleyJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - b2Vec2 m_groundAnchorA; - b2Vec2 m_groundAnchorB; - float32 m_lengthA; - float32 m_lengthB; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_constant; - float32 m_ratio; - float32 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_uA; - b2Vec2 m_uB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp b/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp deleted file mode 100644 index e265d8192b..0000000000 --- a/external/box2d/Dynamics/Joints/b2RevoluteJoint.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// C = p2 - p1 -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Motor constraint -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_referenceAngle = def->referenceAngle; - - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - - m_lowerAngle = def->lowerAngle; - m_upperAngle = def->upperAngle; - m_maxMotorTorque = def->maxMotorTorque; - m_motorSpeed = def->motorSpeed; - m_enableLimit = def->enableLimit; - m_enableMotor = def->enableMotor; - m_limitState = e_inactiveLimit; -} - -void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - bool fixedRotation = (iA + iB == 0.0f); - - m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; - m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; - m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; - m_mass.ex.y = m_mass.ey.x; - m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; - m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; - m_mass.ex.z = m_mass.ez.x; - m_mass.ey.z = m_mass.ez.y; - m_mass.ez.z = iA + iB; - - m_motorMass = iA + iB; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - - if (m_enableMotor == false || fixedRotation) - { - m_motorImpulse = 0.0f; - } - - if (m_enableLimit && fixedRotation == false) - { - float32 jointAngle = aB - aA - m_referenceAngle; - if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) - { - m_limitState = e_equalLimits; - } - else if (jointAngle <= m_lowerAngle) - { - if (m_limitState != e_atLowerLimit) - { - m_impulse.z = 0.0f; - } - m_limitState = e_atLowerLimit; - } - else if (jointAngle >= m_upperAngle) - { - if (m_limitState != e_atUpperLimit) - { - m_impulse.z = 0.0f; - } - m_limitState = e_atUpperLimit; - } - else - { - m_limitState = e_inactiveLimit; - m_impulse.z = 0.0f; - } - } - else - { - m_limitState = e_inactiveLimit; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_impulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P(m_impulse.x, m_impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); - } - else - { - m_impulse.SetZero(); - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - bool fixedRotation = (iA + iB == 0.0f); - - // Solve motor constraint. - if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) - { - float32 Cdot = wB - wA - m_motorSpeed; - float32 impulse = -m_motorMass * Cdot; - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorTorque; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve limit constraint. - if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) - { - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - float32 Cdot2 = wB - wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 impulse = -m_mass.Solve33(Cdot); - - if (m_limitState == e_equalLimits) - { - m_impulse += impulse; - } - else if (m_limitState == e_atLowerLimit) - { - float32 newImpulse = m_impulse.z + impulse.z; - if (newImpulse < 0.0f) - { - b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); - b2Vec2 reduced = m_mass.Solve22(rhs); - impulse.x = reduced.x; - impulse.y = reduced.y; - impulse.z = -m_impulse.z; - m_impulse.x += reduced.x; - m_impulse.y += reduced.y; - m_impulse.z = 0.0f; - } - else - { - m_impulse += impulse; - } - } - else if (m_limitState == e_atUpperLimit) - { - float32 newImpulse = m_impulse.z + impulse.z; - if (newImpulse > 0.0f) - { - b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); - b2Vec2 reduced = m_mass.Solve22(rhs); - impulse.x = reduced.x; - impulse.y = reduced.y; - impulse.z = -m_impulse.z; - m_impulse.x += reduced.x; - m_impulse.y += reduced.y; - m_impulse.z = 0.0f; - } - else - { - m_impulse += impulse; - } - } - - b2Vec2 P(impulse.x, impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + impulse.z); - } - else - { - // Solve point-to-point constraint - b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - b2Vec2 impulse = m_mass.Solve22(-Cdot); - - m_impulse.x += impulse.x; - m_impulse.y += impulse.y; - - vA -= mA * impulse; - wA -= iA * b2Cross(m_rA, impulse); - - vB += mB * impulse; - wB += iB * b2Cross(m_rB, impulse); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 angularError = 0.0f; - float32 positionError = 0.0f; - - bool fixedRotation = (m_invIA + m_invIB == 0.0f); - - // Solve angular limit constraint. - if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) - { - float32 angle = aB - aA - m_referenceAngle; - float32 limitImpulse = 0.0f; - - if (m_limitState == e_equalLimits) - { - // Prevent large angular corrections - float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); - limitImpulse = -m_motorMass * C; - angularError = b2Abs(C); - } - else if (m_limitState == e_atLowerLimit) - { - float32 C = angle - m_lowerAngle; - angularError = -C; - - // Prevent large angular corrections and allow some slop. - C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); - limitImpulse = -m_motorMass * C; - } - else if (m_limitState == e_atUpperLimit) - { - float32 C = angle - m_upperAngle; - angularError = C; - - // Prevent large angular corrections and allow some slop. - C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); - limitImpulse = -m_motorMass * C; - } - - aA -= m_invIA * limitImpulse; - aB += m_invIB * limitImpulse; - } - - // Solve point-to-point constraint. - { - qA.Set(aA); - qB.Set(aB); - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - b2Vec2 C = cB + rB - cA - rA; - positionError = C.Length(); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat22 K; - K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; - K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; - K.ey.x = K.ex.y; - K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; - - b2Vec2 impulse = -K.Solve(C); - - cA -= mA * impulse; - aA -= iA * b2Cross(rA, impulse); - - cB += mB * impulse; - aB += iB * b2Cross(rB, impulse); - } - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return positionError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2RevoluteJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2RevoluteJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P(m_impulse.x, m_impulse.y); - return inv_dt * P; -} - -float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.z; -} - -float32 b2RevoluteJoint::GetJointAngle() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; -} - -float32 b2RevoluteJoint::GetJointSpeed() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - return bB->m_angularVelocity - bA->m_angularVelocity; -} - -bool b2RevoluteJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2RevoluteJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2RevoluteJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorTorque = torque; -} - -bool b2RevoluteJoint::IsLimitEnabled() const -{ - return m_enableLimit; -} - -void b2RevoluteJoint::EnableLimit(bool flag) -{ - if (flag != m_enableLimit) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableLimit = flag; - m_impulse.z = 0.0f; - } -} - -float32 b2RevoluteJoint::GetLowerLimit() const -{ - return m_lowerAngle; -} - -float32 b2RevoluteJoint::GetUpperLimit() const -{ - return m_upperAngle; -} - -void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) -{ - b2Assert(lower <= upper); - - if (lower != m_lowerAngle || upper != m_upperAngle) - { - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_impulse.z = 0.0f; - m_lowerAngle = lower; - m_upperAngle = upper; - } -} - -void b2RevoluteJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2RevoluteJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); - b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); - b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2RevoluteJoint.h b/external/box2d/Dynamics/Joints/b2RevoluteJoint.h deleted file mode 100644 index 978f16259a..0000000000 --- a/external/box2d/Dynamics/Joints/b2RevoluteJoint.h +++ /dev/null @@ -1,204 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_REVOLUTE_JOINT_H -#define B2_REVOLUTE_JOINT_H - -#include - -/// Revolute joint definition. This requires defining an -/// anchor point where the bodies are joined. The definition -/// uses local anchor points so that the initial configuration -/// can violate the constraint slightly. You also need to -/// specify the initial relative angle for joint limits. This -/// helps when saving and loading a game. -/// The local anchor points are measured from the body's origin -/// rather than the center of mass because: -/// 1. you might not know where the center of mass will be. -/// 2. if you add/remove shapes from a body and recompute the mass, -/// the joints will be broken. -struct b2RevoluteJointDef : public b2JointDef -{ - b2RevoluteJointDef() - { - type = e_revoluteJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - referenceAngle = 0.0f; - lowerAngle = 0.0f; - upperAngle = 0.0f; - maxMotorTorque = 0.0f; - motorSpeed = 0.0f; - enableLimit = false; - enableMotor = false; - } - - /// Initialize the bodies, anchors, and reference angle using a world - /// anchor point. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The bodyB angle minus bodyA angle in the reference state (radians). - float32 referenceAngle; - - /// A flag to enable joint limits. - bool enableLimit; - - /// The lower angle for the joint limit (radians). - float32 lowerAngle; - - /// The upper angle for the joint limit (radians). - float32 upperAngle; - - /// A flag to enable the joint motor. - bool enableMotor; - - /// The desired motor speed. Usually in radians per second. - float32 motorSpeed; - - /// The maximum motor torque used to achieve the desired motor speed. - /// Usually in N-m. - float32 maxMotorTorque; -}; - -/// A revolute joint constrains two bodies to share a common point while they -/// are free to rotate about the point. The relative rotation about the shared -/// point is the joint angle. You can limit the relative rotation with -/// a joint limit that specifies a lower and upper angle. You can use a motor -/// to drive the relative rotation about the shared point. A maximum motor torque -/// is provided so that infinite forces are not generated. -class b2RevoluteJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Get the current joint angle in radians. - float32 GetJointAngle() const; - - /// Get the current joint angle speed in radians per second. - float32 GetJointSpeed() const; - - /// Is the joint limit enabled? - bool IsLimitEnabled() const; - - /// Enable/disable the joint limit. - void EnableLimit(bool flag); - - /// Get the lower joint limit in radians. - float32 GetLowerLimit() const; - - /// Get the upper joint limit in radians. - float32 GetUpperLimit() const; - - /// Set the joint limits in radians. - void SetLimits(float32 lower, float32 upper); - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed in radians per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed in radians per second. - float32 GetMotorSpeed() const; - - /// Set the maximum motor torque, usually in N-m. - void SetMaxMotorTorque(float32 torque); - float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } - - /// Get the reaction force given the inverse time step. - /// Unit is N. - b2Vec2 GetReactionForce(float32 inv_dt) const; - - /// Get the reaction torque due to the joint limit given the inverse time step. - /// Unit is N*m. - float32 GetReactionTorque(float32 inv_dt) const; - - /// Get the current motor torque given the inverse time step. - /// Unit is N*m. - float32 GetMotorTorque(float32 inv_dt) const; - - /// Dump to b2Log. - void Dump(); - -protected: - - friend class b2Joint; - friend class b2GearJoint; - - b2RevoluteJoint(const b2RevoluteJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec3 m_impulse; - float32 m_motorImpulse; - - bool m_enableMotor; - float32 m_maxMotorTorque; - float32 m_motorSpeed; - - bool m_enableLimit; - float32 m_referenceAngle; - float32 m_lowerAngle; - float32 m_upperAngle; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat33 m_mass; // effective mass for point-to-point constraint. - float32 m_motorMass; // effective mass for motor/limit angular constraint. - b2LimitState m_limitState; -}; - -inline float32 b2RevoluteJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -#endif diff --git a/external/box2d/Dynamics/Joints/b2RopeJoint.cpp b/external/box2d/Dynamics/Joints/b2RopeJoint.cpp deleted file mode 100644 index 17a70d9230..0000000000 --- a/external/box2d/Dynamics/Joints/b2RopeJoint.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* -* Copyright (c) 2007-2011 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 -#include -#include - - -// Limit: -// C = norm(pB - pA) - L -// u = (pB - pA) / norm(pB - pA) -// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) -// J = [-u -cross(rA, u) u cross(rB, u)] -// K = J * invM * JT -// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 - -b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - - m_maxLength = def->maxLength; - - m_mass = 0.0f; - m_impulse = 0.0f; - m_state = e_inactiveLimit; - m_length = 0.0f; -} - -void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - m_u = cB + m_rB - cA - m_rA; - - m_length = m_u.Length(); - - float32 C = m_length - m_maxLength; - if (C > 0.0f) - { - m_state = e_atUpperLimit; - } - else - { - m_state = e_inactiveLimit; - } - - if (m_length > b2_linearSlop) - { - m_u *= 1.0f / m_length; - } - else - { - m_u.SetZero(); - m_mass = 0.0f; - m_impulse = 0.0f; - return; - } - - // Compute effective mass. - float32 crA = b2Cross(m_rA, m_u); - float32 crB = b2Cross(m_rB, m_u); - float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; - - m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; - - if (data.step.warmStarting) - { - // Scale the impulse to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - } - else - { - m_impulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Cdot = dot(u, v + cross(w, r)) - b2Vec2 vpA = vA + b2Cross(wA, m_rA); - b2Vec2 vpB = vB + b2Cross(wB, m_rB); - float32 C = m_length - m_maxLength; - float32 Cdot = b2Dot(m_u, vpB - vpA); - - // Predictive constraint. - if (C < 0.0f) - { - Cdot += data.step.inv_dt * C; - } - - float32 impulse = -m_mass * Cdot; - float32 oldImpulse = m_impulse; - m_impulse = b2Min(0.0f, m_impulse + impulse); - impulse = m_impulse - oldImpulse; - - b2Vec2 P = impulse * m_u; - vA -= m_invMassA * P; - wA -= m_invIA * b2Cross(m_rA, P); - vB += m_invMassB * P; - wB += m_invIB * b2Cross(m_rB, P); - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 u = cB + rB - cA - rA; - - float32 length = u.Normalize(); - float32 C = length - m_maxLength; - - C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); - - float32 impulse = -m_mass * C; - b2Vec2 P = impulse * u; - - cA -= m_invMassA * P; - aA -= m_invIA * b2Cross(rA, P); - cB += m_invMassB * P; - aB += m_invIB * b2Cross(rB, P); - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return length - m_maxLength < b2_linearSlop; -} - -b2Vec2 b2RopeJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2RopeJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 F = (inv_dt * m_impulse) * m_u; - return F; -} - -float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const -{ - B2_NOT_USED(inv_dt); - return 0.0f; -} - -float32 b2RopeJoint::GetMaxLength() const -{ - return m_maxLength; -} - -b2LimitState b2RopeJoint::GetLimitState() const -{ - return m_state; -} - -void b2RopeJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2RopeJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2RopeJoint.h b/external/box2d/Dynamics/Joints/b2RopeJoint.h deleted file mode 100644 index d7091b6650..0000000000 --- a/external/box2d/Dynamics/Joints/b2RopeJoint.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_ROPE_JOINT_H -#define B2_ROPE_JOINT_H - -#include - -/// Rope joint definition. This requires two body anchor points and -/// a maximum lengths. -/// Note: by default the connected objects will not collide. -/// see collideConnected in b2JointDef. -struct b2RopeJointDef : public b2JointDef -{ - b2RopeJointDef() - { - type = e_ropeJoint; - localAnchorA.Set(-1.0f, 0.0f); - localAnchorB.Set(1.0f, 0.0f); - maxLength = 0.0f; - } - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The maximum length of the rope. - /// Warning: this must be larger than b2_linearSlop or - /// the joint will have no effect. - float32 maxLength; -}; - -/// A rope joint enforces a maximum distance between two points -/// on two bodies. It has no other effect. -/// Warning: if you attempt to change the maximum length during -/// the simulation you will get some non-physical behavior. -/// A model that would allow you to dynamically modify the length -/// would have some sponginess, so I chose not to implement it -/// that way. See b2DistanceJoint if you want to dynamically -/// control length. -class b2RopeJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Set/Get the maximum length of the rope. - void SetMaxLength(float32 length) { m_maxLength = length; } - float32 GetMaxLength() const; - - b2LimitState GetLimitState() const; - - /// Dump joint to dmLog - void Dump(); - -protected: - - friend class b2Joint; - b2RopeJoint(const b2RopeJointDef* data); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_maxLength; - float32 m_length; - float32 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_u; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - float32 m_mass; - b2LimitState m_state; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2WeldJoint.cpp b/external/box2d/Dynamics/Joints/b2WeldJoint.cpp deleted file mode 100644 index f50bdd6587..0000000000 --- a/external/box2d/Dynamics/Joints/b2WeldJoint.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include - -// Point-to-point constraint -// C = p2 - p1 -// Cdot = v2 - v1 -// = v2 + cross(w2, r2) - v1 - cross(w1, r1) -// J = [-I -r1_skew I r2_skew ] -// Identity used: -// w k % (rx i + ry j) = w * (-ry i + rx j) - -// Angle constraint -// C = angle2 - angle1 - referenceAngle -// Cdot = w2 - w1 -// J = [0 0 -1 0 0 1] -// K = invI1 + invI2 - -void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); -} - -b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_referenceAngle = def->referenceAngle; - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_impulse.SetZero(); -} - -void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - // J = [-I -r1_skew I r2_skew] - // [ 0 -1 0 1] - // r_skew = [-ry; rx] - - // Matlab - // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] - // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] - // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Mat33 K; - K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; - K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; - K.ez.x = -m_rA.y * iA - m_rB.y * iB; - K.ex.y = K.ey.x; - K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; - K.ez.y = m_rA.x * iA + m_rB.x * iB; - K.ex.z = K.ez.x; - K.ey.z = K.ez.y; - K.ez.z = iA + iB; - - if (m_frequencyHz > 0.0f) - { - K.GetInverse22(&m_mass); - - float32 invM = iA + iB; - float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; - - float32 C = aB - aA - m_referenceAngle; - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; - m_bias = C * h * k * m_gamma; - - invM += m_gamma; - m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; - } - else - { - K.GetSymInverse33(&m_mass); - m_gamma = 0.0f; - m_bias = 0.0f; - } - - if (data.step.warmStarting) - { - // Scale impulses to support a variable time step. - m_impulse *= data.step.dtRatio; - - b2Vec2 P(m_impulse.x, m_impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + m_impulse.z); - } - else - { - m_impulse.SetZero(); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - if (m_frequencyHz > 0.0f) - { - float32 Cdot2 = wB - wA; - - float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); - m_impulse.z += impulse2; - - wA -= iA * impulse2; - wB += iB * impulse2; - - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - - b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); - m_impulse.x += impulse1.x; - m_impulse.y += impulse1.y; - - b2Vec2 P = impulse1; - - vA -= mA * P; - wA -= iA * b2Cross(m_rA, P); - - vB += mB * P; - wB += iB * b2Cross(m_rB, P); - } - else - { - b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); - float32 Cdot2 = wB - wA; - b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); - - b2Vec3 impulse = -b2Mul(m_mass, Cdot); - m_impulse += impulse; - - b2Vec2 P(impulse.x, impulse.y); - - vA -= mA * P; - wA -= iA * (b2Cross(m_rA, P) + impulse.z); - - vB += mB * P; - wB += iB * (b2Cross(m_rB, P) + impulse.z); - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - - float32 positionError, angularError; - - b2Mat33 K; - K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; - K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; - K.ez.x = -rA.y * iA - rB.y * iB; - K.ex.y = K.ey.x; - K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; - K.ez.y = rA.x * iA + rB.x * iB; - K.ex.z = K.ez.x; - K.ey.z = K.ez.y; - K.ez.z = iA + iB; - - if (m_frequencyHz > 0.0f) - { - b2Vec2 C1 = cB + rB - cA - rA; - - positionError = C1.Length(); - angularError = 0.0f; - - b2Vec2 P = -K.Solve22(C1); - - cA -= mA * P; - aA -= iA * b2Cross(rA, P); - - cB += mB * P; - aB += iB * b2Cross(rB, P); - } - else - { - b2Vec2 C1 = cB + rB - cA - rA; - float32 C2 = aB - aA - m_referenceAngle; - - positionError = C1.Length(); - angularError = b2Abs(C2); - - b2Vec3 C(C1.x, C1.y, C2); - - b2Vec3 impulse = -K.Solve33(C); - b2Vec2 P(impulse.x, impulse.y); - - cA -= mA * P; - aA -= iA * (b2Cross(rA, P) + impulse.z); - - cB += mB * P; - aB += iB * (b2Cross(rB, P) + impulse.z); - } - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return positionError <= b2_linearSlop && angularError <= b2_angularSlop; -} - -b2Vec2 b2WeldJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2WeldJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const -{ - b2Vec2 P(m_impulse.x, m_impulse.y); - return inv_dt * P; -} - -float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_impulse.z; -} - -void b2WeldJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2WeldJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2WeldJoint.h b/external/box2d/Dynamics/Joints/b2WeldJoint.h deleted file mode 100644 index 751c6a8770..0000000000 --- a/external/box2d/Dynamics/Joints/b2WeldJoint.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WELD_JOINT_H -#define B2_WELD_JOINT_H - -#include - -/// Weld joint definition. You need to specify local anchor points -/// where they are attached and the relative body angle. The position -/// of the anchor points is important for computing the reaction torque. -struct b2WeldJointDef : public b2JointDef -{ - b2WeldJointDef() - { - type = e_weldJoint; - localAnchorA.Set(0.0f, 0.0f); - localAnchorB.Set(0.0f, 0.0f); - referenceAngle = 0.0f; - frequencyHz = 0.0f; - dampingRatio = 0.0f; - } - - /// Initialize the bodies, anchors, and reference angle using a world - /// anchor point. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The bodyB angle minus bodyA angle in the reference state (radians). - float32 referenceAngle; - - /// The mass-spring-damper frequency in Hertz. Rotation only. - /// Disable softness with a value of 0. - float32 frequencyHz; - - /// The damping ratio. 0 = no damping, 1 = critical damping. - float32 dampingRatio; -}; - -/// A weld joint essentially glues two bodies together. A weld joint may -/// distort somewhat because the island constraint solver is approximate. -class b2WeldJoint : public b2Joint -{ -public: - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// Get the reference angle. - float32 GetReferenceAngle() const { return m_referenceAngle; } - - /// Set/get frequency in Hz. - void SetFrequency(float32 hz) { m_frequencyHz = hz; } - float32 GetFrequency() const { return m_frequencyHz; } - - /// Set/get damping ratio. - void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } - float32 GetDampingRatio() const { return m_dampingRatio; } - - /// Dump to b2Log - void Dump(); - -protected: - - friend class b2Joint; - - b2WeldJoint(const b2WeldJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - float32 m_bias; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - float32 m_referenceAngle; - float32 m_gamma; - b2Vec3 m_impulse; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_rA; - b2Vec2 m_rB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - b2Mat33 m_mass; -}; - -#endif diff --git a/external/box2d/Dynamics/Joints/b2WheelJoint.cpp b/external/box2d/Dynamics/Joints/b2WheelJoint.cpp deleted file mode 100644 index 6253437706..0000000000 --- a/external/box2d/Dynamics/Joints/b2WheelJoint.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include - -// Linear constraint (point-to-line) -// d = pB - pA = xB + rB - xA - rA -// C = dot(ay, d) -// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) -// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) -// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] - -// Spring linear constraint -// C = dot(ax, d) -// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) -// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] - -// Motor rotational constraint -// Cdot = wB - wA -// J = [0 0 -1 0 0 1] - -void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) -{ - bodyA = bA; - bodyB = bB; - localAnchorA = bodyA->GetLocalPoint(anchor); - localAnchorB = bodyB->GetLocalPoint(anchor); - localAxisA = bodyA->GetLocalVector(axis); -} - -b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) -: b2Joint(def) -{ - m_localAnchorA = def->localAnchorA; - m_localAnchorB = def->localAnchorB; - m_localXAxisA = def->localAxisA; - m_localYAxisA = b2Cross(1.0f, m_localXAxisA); - - m_mass = 0.0f; - m_impulse = 0.0f; - m_motorMass = 0.0; - m_motorImpulse = 0.0f; - m_springMass = 0.0f; - m_springImpulse = 0.0f; - - m_maxMotorTorque = def->maxMotorTorque; - m_motorSpeed = def->motorSpeed; - m_enableMotor = def->enableMotor; - - m_frequencyHz = def->frequencyHz; - m_dampingRatio = def->dampingRatio; - - m_bias = 0.0f; - m_gamma = 0.0f; - - m_ax.SetZero(); - m_ay.SetZero(); -} - -void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) -{ - m_indexA = m_bodyA->m_islandIndex; - m_indexB = m_bodyB->m_islandIndex; - m_localCenterA = m_bodyA->m_sweep.localCenter; - m_localCenterB = m_bodyB->m_sweep.localCenter; - m_invMassA = m_bodyA->m_invMass; - m_invMassB = m_bodyB->m_invMass; - m_invIA = m_bodyA->m_invI; - m_invIB = m_bodyB->m_invI; - - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - b2Rot qA(aA), qB(aB); - - // Compute the effective masses. - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = cB + rB - cA - rA; - - // Point to line constraint - { - m_ay = b2Mul(qA, m_localYAxisA); - m_sAy = b2Cross(d + rA, m_ay); - m_sBy = b2Cross(rB, m_ay); - - m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; - - if (m_mass > 0.0f) - { - m_mass = 1.0f / m_mass; - } - } - - // Spring constraint - m_springMass = 0.0f; - m_bias = 0.0f; - m_gamma = 0.0f; - if (m_frequencyHz > 0.0f) - { - m_ax = b2Mul(qA, m_localXAxisA); - m_sAx = b2Cross(d + rA, m_ax); - m_sBx = b2Cross(rB, m_ax); - - float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; - - if (invMass > 0.0f) - { - m_springMass = 1.0f / invMass; - - float32 C = b2Dot(d, m_ax); - - // Frequency - float32 omega = 2.0f * b2_pi * m_frequencyHz; - - // Damping coefficient - float32 d = 2.0f * m_springMass * m_dampingRatio * omega; - - // Spring stiffness - float32 k = m_springMass * omega * omega; - - // magic formulas - float32 h = data.step.dt; - m_gamma = h * (d + h * k); - if (m_gamma > 0.0f) - { - m_gamma = 1.0f / m_gamma; - } - - m_bias = C * h * k * m_gamma; - - m_springMass = invMass + m_gamma; - if (m_springMass > 0.0f) - { - m_springMass = 1.0f / m_springMass; - } - } - } - else - { - m_springImpulse = 0.0f; - } - - // Rotational motor - if (m_enableMotor) - { - m_motorMass = iA + iB; - if (m_motorMass > 0.0f) - { - m_motorMass = 1.0f / m_motorMass; - } - } - else - { - m_motorMass = 0.0f; - m_motorImpulse = 0.0f; - } - - if (data.step.warmStarting) - { - // Account for variable time step. - m_impulse *= data.step.dtRatio; - m_springImpulse *= data.step.dtRatio; - m_motorImpulse *= data.step.dtRatio; - - b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; - float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; - float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; - - vA -= m_invMassA * P; - wA -= m_invIA * LA; - - vB += m_invMassB * P; - wB += m_invIB * LB; - } - else - { - m_impulse = 0.0f; - m_springImpulse = 0.0f; - m_motorImpulse = 0.0f; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) -{ - float32 mA = m_invMassA, mB = m_invMassB; - float32 iA = m_invIA, iB = m_invIB; - - b2Vec2 vA = data.velocities[m_indexA].v; - float32 wA = data.velocities[m_indexA].w; - b2Vec2 vB = data.velocities[m_indexB].v; - float32 wB = data.velocities[m_indexB].w; - - // Solve spring constraint - { - float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; - float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); - m_springImpulse += impulse; - - b2Vec2 P = impulse * m_ax; - float32 LA = impulse * m_sAx; - float32 LB = impulse * m_sBx; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - // Solve rotational motor constraint - { - float32 Cdot = wB - wA - m_motorSpeed; - float32 impulse = -m_motorMass * Cdot; - - float32 oldImpulse = m_motorImpulse; - float32 maxImpulse = data.step.dt * m_maxMotorTorque; - m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); - impulse = m_motorImpulse - oldImpulse; - - wA -= iA * impulse; - wB += iB * impulse; - } - - // Solve point to line constraint - { - float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; - float32 impulse = -m_mass * Cdot; - m_impulse += impulse; - - b2Vec2 P = impulse * m_ay; - float32 LA = impulse * m_sAy; - float32 LB = impulse * m_sBy; - - vA -= mA * P; - wA -= iA * LA; - - vB += mB * P; - wB += iB * LB; - } - - data.velocities[m_indexA].v = vA; - data.velocities[m_indexA].w = wA; - data.velocities[m_indexB].v = vB; - data.velocities[m_indexB].w = wB; -} - -bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) -{ - b2Vec2 cA = data.positions[m_indexA].c; - float32 aA = data.positions[m_indexA].a; - b2Vec2 cB = data.positions[m_indexB].c; - float32 aB = data.positions[m_indexB].a; - - b2Rot qA(aA), qB(aB); - - b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); - b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); - b2Vec2 d = (cB - cA) + rB - rA; - - b2Vec2 ay = b2Mul(qA, m_localYAxisA); - - float32 sAy = b2Cross(d + rA, ay); - float32 sBy = b2Cross(rB, ay); - - float32 C = b2Dot(d, ay); - - float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; - - float32 impulse; - if (k != 0.0f) - { - impulse = - C / k; - } - else - { - impulse = 0.0f; - } - - b2Vec2 P = impulse * ay; - float32 LA = impulse * sAy; - float32 LB = impulse * sBy; - - cA -= m_invMassA * P; - aA -= m_invIA * LA; - cB += m_invMassB * P; - aB += m_invIB * LB; - - data.positions[m_indexA].c = cA; - data.positions[m_indexA].a = aA; - data.positions[m_indexB].c = cB; - data.positions[m_indexB].a = aB; - - return b2Abs(C) <= b2_linearSlop; -} - -b2Vec2 b2WheelJoint::GetAnchorA() const -{ - return m_bodyA->GetWorldPoint(m_localAnchorA); -} - -b2Vec2 b2WheelJoint::GetAnchorB() const -{ - return m_bodyB->GetWorldPoint(m_localAnchorB); -} - -b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const -{ - return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); -} - -float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -float32 b2WheelJoint::GetJointTranslation() const -{ - b2Body* bA = m_bodyA; - b2Body* bB = m_bodyB; - - b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); - b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); - b2Vec2 d = pB - pA; - b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); - - float32 translation = b2Dot(d, axis); - return translation; -} - -float32 b2WheelJoint::GetJointSpeed() const -{ - float32 wA = m_bodyA->m_angularVelocity; - float32 wB = m_bodyB->m_angularVelocity; - return wB - wA; -} - -bool b2WheelJoint::IsMotorEnabled() const -{ - return m_enableMotor; -} - -void b2WheelJoint::EnableMotor(bool flag) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_enableMotor = flag; -} - -void b2WheelJoint::SetMotorSpeed(float32 speed) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_motorSpeed = speed; -} - -void b2WheelJoint::SetMaxMotorTorque(float32 torque) -{ - m_bodyA->SetAwake(true); - m_bodyB->SetAwake(true); - m_maxMotorTorque = torque; -} - -float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const -{ - return inv_dt * m_motorImpulse; -} - -void b2WheelJoint::Dump() -{ - int32 indexA = m_bodyA->m_islandIndex; - int32 indexB = m_bodyB->m_islandIndex; - - b2Log(" b2WheelJointDef jd;\n"); - b2Log(" jd.bodyA = bodies[%d];\n", indexA); - b2Log(" jd.bodyB = bodies[%d];\n", indexB); - b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); - b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); - b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); - b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); - b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); - b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); - b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); - b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); - b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); - b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); -} diff --git a/external/box2d/Dynamics/Joints/b2WheelJoint.h b/external/box2d/Dynamics/Joints/b2WheelJoint.h deleted file mode 100644 index ede1b08b7c..0000000000 --- a/external/box2d/Dynamics/Joints/b2WheelJoint.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WHEEL_JOINT_H -#define B2_WHEEL_JOINT_H - -#include - -/// Wheel joint definition. This requires defining a line of -/// motion using an axis and an anchor point. The definition uses local -/// anchor points and a local axis so that the initial configuration -/// can violate the constraint slightly. The joint translation is zero -/// when the local anchor points coincide in world space. Using local -/// anchors and a local axis helps when saving and loading a game. -struct b2WheelJointDef : public b2JointDef -{ - b2WheelJointDef() - { - type = e_wheelJoint; - localAnchorA.SetZero(); - localAnchorB.SetZero(); - localAxisA.Set(1.0f, 0.0f); - enableMotor = false; - maxMotorTorque = 0.0f; - motorSpeed = 0.0f; - frequencyHz = 2.0f; - dampingRatio = 0.7f; - } - - /// Initialize the bodies, anchors, axis, and reference angle using the world - /// anchor and world axis. - void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); - - /// The local anchor point relative to bodyA's origin. - b2Vec2 localAnchorA; - - /// The local anchor point relative to bodyB's origin. - b2Vec2 localAnchorB; - - /// The local translation axis in bodyA. - b2Vec2 localAxisA; - - /// Enable/disable the joint motor. - bool enableMotor; - - /// The maximum motor torque, usually in N-m. - float32 maxMotorTorque; - - /// The desired motor speed in radians per second. - float32 motorSpeed; - - /// Suspension frequency, zero indicates no suspension - float32 frequencyHz; - - /// Suspension damping ratio, one indicates critical damping - float32 dampingRatio; -}; - -/// A wheel joint. This joint provides two degrees of freedom: translation -/// along an axis fixed in bodyA and rotation in the plane. You can use a -/// joint limit to restrict the range of motion and a joint motor to drive -/// the rotation or to model rotational friction. -/// This joint is designed for vehicle suspensions. -class b2WheelJoint : public b2Joint -{ -public: - void GetDefinition(b2WheelJointDef* def) const; - - b2Vec2 GetAnchorA() const; - b2Vec2 GetAnchorB() const; - - b2Vec2 GetReactionForce(float32 inv_dt) const; - float32 GetReactionTorque(float32 inv_dt) const; - - /// The local anchor point relative to bodyA's origin. - const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } - - /// The local anchor point relative to bodyB's origin. - const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } - - /// The local joint axis relative to bodyA. - const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } - - /// Get the current joint translation, usually in meters. - float32 GetJointTranslation() const; - - /// Get the current joint translation speed, usually in meters per second. - float32 GetJointSpeed() const; - - /// Is the joint motor enabled? - bool IsMotorEnabled() const; - - /// Enable/disable the joint motor. - void EnableMotor(bool flag); - - /// Set the motor speed, usually in radians per second. - void SetMotorSpeed(float32 speed); - - /// Get the motor speed, usually in radians per second. - float32 GetMotorSpeed() const; - - /// Set/Get the maximum motor force, usually in N-m. - void SetMaxMotorTorque(float32 torque); - float32 GetMaxMotorTorque() const; - - /// Get the current motor torque given the inverse time step, usually in N-m. - float32 GetMotorTorque(float32 inv_dt) const; - - /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. - void SetSpringFrequencyHz(float32 hz); - float32 GetSpringFrequencyHz() const; - - /// Set/Get the spring damping ratio - void SetSpringDampingRatio(float32 ratio); - float32 GetSpringDampingRatio() const; - - /// Dump to b2Log - void Dump(); - -protected: - - friend class b2Joint; - b2WheelJoint(const b2WheelJointDef* def); - - void InitVelocityConstraints(const b2SolverData& data); - void SolveVelocityConstraints(const b2SolverData& data); - bool SolvePositionConstraints(const b2SolverData& data); - - float32 m_frequencyHz; - float32 m_dampingRatio; - - // Solver shared - b2Vec2 m_localAnchorA; - b2Vec2 m_localAnchorB; - b2Vec2 m_localXAxisA; - b2Vec2 m_localYAxisA; - - float32 m_impulse; - float32 m_motorImpulse; - float32 m_springImpulse; - - float32 m_maxMotorTorque; - float32 m_motorSpeed; - bool m_enableMotor; - - // Solver temp - int32 m_indexA; - int32 m_indexB; - b2Vec2 m_localCenterA; - b2Vec2 m_localCenterB; - float32 m_invMassA; - float32 m_invMassB; - float32 m_invIA; - float32 m_invIB; - - b2Vec2 m_ax, m_ay; - float32 m_sAx, m_sBx; - float32 m_sAy, m_sBy; - - float32 m_mass; - float32 m_motorMass; - float32 m_springMass; - - float32 m_bias; - float32 m_gamma; -}; - -inline float32 b2WheelJoint::GetMotorSpeed() const -{ - return m_motorSpeed; -} - -inline float32 b2WheelJoint::GetMaxMotorTorque() const -{ - return m_maxMotorTorque; -} - -inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) -{ - m_frequencyHz = hz; -} - -inline float32 b2WheelJoint::GetSpringFrequencyHz() const -{ - return m_frequencyHz; -} - -inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) -{ - m_dampingRatio = ratio; -} - -inline float32 b2WheelJoint::GetSpringDampingRatio() const -{ - return m_dampingRatio; -} - -#endif diff --git a/external/box2d/Dynamics/b2Body.cpp b/external/box2d/Dynamics/b2Body.cpp deleted file mode 100644 index b22b574023..0000000000 --- a/external/box2d/Dynamics/b2Body.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* -* Copyright (c) 2006-2007 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 -#include -#include -#include -#include - -b2Body::b2Body(const b2BodyDef* bd, b2World* world) -{ - b2Assert(bd->position.IsValid()); - b2Assert(bd->linearVelocity.IsValid()); - b2Assert(b2IsValid(bd->angle)); - b2Assert(b2IsValid(bd->angularVelocity)); - b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); - b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); - - m_flags = 0; - - if (bd->bullet) - { - m_flags |= e_bulletFlag; - } - if (bd->fixedRotation) - { - m_flags |= e_fixedRotationFlag; - } - if (bd->allowSleep) - { - m_flags |= e_autoSleepFlag; - } - if (bd->awake) - { - m_flags |= e_awakeFlag; - } - if (bd->active) - { - m_flags |= e_activeFlag; - } - - m_world = world; - - m_xf.p = bd->position; - m_xf.q.Set(bd->angle); - - m_sweep.localCenter.SetZero(); - m_sweep.c0 = m_xf.p; - m_sweep.c = m_xf.p; - m_sweep.a0 = bd->angle; - m_sweep.a = bd->angle; - m_sweep.alpha0 = 0.0f; - - m_jointList = NULL; - m_contactList = NULL; - m_prev = NULL; - m_next = NULL; - - m_linearVelocity = bd->linearVelocity; - m_angularVelocity = bd->angularVelocity; - - m_linearDamping = bd->linearDamping; - m_angularDamping = bd->angularDamping; - m_gravityScale = bd->gravityScale; - - m_force.SetZero(); - m_torque = 0.0f; - - m_sleepTime = 0.0f; - - m_type = bd->type; - - if (m_type == b2_dynamicBody) - { - m_mass = 1.0f; - m_invMass = 1.0f; - } - else - { - m_mass = 0.0f; - m_invMass = 0.0f; - } - - m_I = 0.0f; - m_invI = 0.0f; - - m_userData = bd->userData; - - m_fixtureList = NULL; - m_fixtureCount = 0; -} - -b2Body::~b2Body() -{ - // shapes and joints are destroyed in b2World::Destroy -} - -void b2Body::SetType(b2BodyType type) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - if (m_type == type) - { - return; - } - - m_type = type; - - ResetMassData(); - - if (m_type == b2_staticBody) - { - m_linearVelocity.SetZero(); - m_angularVelocity = 0.0f; - m_sweep.a0 = m_sweep.a; - m_sweep.c0 = m_sweep.c; - SynchronizeFixtures(); - } - - SetAwake(true); - - m_force.SetZero(); - m_torque = 0.0f; - - // Since the body type changed, we need to flag contacts for filtering. - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Refilter(); - } -} - -b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return NULL; - } - - b2BlockAllocator* allocator = &m_world->m_blockAllocator; - - void* memory = allocator->Allocate(sizeof(b2Fixture)); - b2Fixture* fixture = new (memory) b2Fixture; - fixture->Create(allocator, this, def); - - if (m_flags & e_activeFlag) - { - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - fixture->CreateProxies(broadPhase, m_xf); - } - - fixture->m_next = m_fixtureList; - m_fixtureList = fixture; - ++m_fixtureCount; - - fixture->m_body = this; - - // Adjust mass properties if needed. - if (fixture->m_density > 0.0f) - { - ResetMassData(); - } - - // Let the world know we have a new fixture. This will cause new contacts - // to be created at the beginning of the next time step. - m_world->m_flags |= b2World::e_newFixture; - - return fixture; -} - -b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) -{ - b2FixtureDef def; - def.shape = shape; - def.density = density; - - return CreateFixture(&def); -} - -void b2Body::DestroyFixture(b2Fixture* fixture) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - b2Assert(fixture->m_body == this); - - // Remove the fixture from this body's singly linked list. - b2Assert(m_fixtureCount > 0); - b2Fixture** node = &m_fixtureList; - bool found = false; - while (*node != NULL) - { - if (*node == fixture) - { - *node = fixture->m_next; - found = true; - break; - } - - node = &(*node)->m_next; - } - - // You tried to remove a shape that is not attached to this body. - b2Assert(found); - - // Destroy any contacts associated with the fixture. - b2ContactEdge* edge = m_contactList; - while (edge) - { - b2Contact* c = edge->contact; - edge = edge->next; - - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - - if (fixture == fixtureA || fixture == fixtureB) - { - // This destroys the contact and removes it from - // this body's contact list. - m_world->m_contactManager.Destroy(c); - } - } - - b2BlockAllocator* allocator = &m_world->m_blockAllocator; - - if (m_flags & e_activeFlag) - { - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - fixture->DestroyProxies(broadPhase); - } - - fixture->Destroy(allocator); - fixture->m_body = NULL; - fixture->m_next = NULL; - fixture->~b2Fixture(); - allocator->Free(fixture, sizeof(b2Fixture)); - - --m_fixtureCount; - - // Reset the mass data. - ResetMassData(); -} - -void b2Body::ResetMassData() -{ - // Compute mass data from shapes. Each shape has its own density. - m_mass = 0.0f; - m_invMass = 0.0f; - m_I = 0.0f; - m_invI = 0.0f; - m_sweep.localCenter.SetZero(); - - // Static and kinematic bodies have zero mass. - if (m_type == b2_staticBody || m_type == b2_kinematicBody) - { - m_sweep.c0 = m_xf.p; - m_sweep.c = m_xf.p; - m_sweep.a0 = m_sweep.a; - return; - } - - b2Assert(m_type == b2_dynamicBody); - - // Accumulate mass over all fixtures. - b2Vec2 localCenter = b2Vec2_zero; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - if (f->m_density == 0.0f) - { - continue; - } - - b2MassData massData; - f->GetMassData(&massData); - m_mass += massData.mass; - localCenter += massData.mass * massData.center; - m_I += massData.I; - } - - // Compute center of mass. - if (m_mass > 0.0f) - { - m_invMass = 1.0f / m_mass; - localCenter *= m_invMass; - } - else - { - // Force all dynamic bodies to have a positive mass. - m_mass = 1.0f; - m_invMass = 1.0f; - } - - if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) - { - // Center the inertia about the center of mass. - m_I -= m_mass * b2Dot(localCenter, localCenter); - b2Assert(m_I > 0.0f); - m_invI = 1.0f / m_I; - - } - else - { - m_I = 0.0f; - m_invI = 0.0f; - } - - // Move center of mass. - b2Vec2 oldCenter = m_sweep.c; - m_sweep.localCenter = localCenter; - m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - - // Update center of mass velocity. - m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); -} - -void b2Body::SetMassData(const b2MassData* massData) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - if (m_type != b2_dynamicBody) - { - return; - } - - m_invMass = 0.0f; - m_I = 0.0f; - m_invI = 0.0f; - - m_mass = massData->mass; - if (m_mass <= 0.0f) - { - m_mass = 1.0f; - } - - m_invMass = 1.0f / m_mass; - - if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) - { - m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); - b2Assert(m_I > 0.0f); - m_invI = 1.0f / m_I; - } - - // Move center of mass. - b2Vec2 oldCenter = m_sweep.c; - m_sweep.localCenter = massData->center; - m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - - // Update center of mass velocity. - m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); -} - -bool b2Body::ShouldCollide(const b2Body* other) const -{ - // At least one body should be dynamic. - if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) - { - return false; - } - - // Does a joint prevent collision? - for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) - { - if (jn->other == other) - { - if (jn->joint->m_collideConnected == false) - { - return false; - } - } - } - - return true; -} - -void b2Body::SetTransform(const b2Vec2& position, float32 angle) -{ - b2Assert(m_world->IsLocked() == false); - if (m_world->IsLocked() == true) - { - return; - } - - m_xf.q.Set(angle); - m_xf.p = position; - - m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); - m_sweep.a = angle; - - m_sweep.c0 = m_sweep.c; - m_sweep.a0 = angle; - - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Synchronize(broadPhase, m_xf, m_xf); - } - - m_world->m_contactManager.FindNewContacts(); -} - -void b2Body::SynchronizeFixtures() -{ - b2Transform xf1; - xf1.q.Set(m_sweep.a0); - xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); - - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->Synchronize(broadPhase, xf1, m_xf); - } -} - -void b2Body::SetActive(bool flag) -{ - b2Assert(m_world->IsLocked() == false); - - if (flag == IsActive()) - { - return; - } - - if (flag) - { - m_flags |= e_activeFlag; - - // Create all proxies. - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->CreateProxies(broadPhase, m_xf); - } - - // Contacts are created the next time step. - } - else - { - m_flags &= ~e_activeFlag; - - // Destroy all proxies. - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - f->DestroyProxies(broadPhase); - } - - // Destroy the attached contacts. - b2ContactEdge* ce = m_contactList; - while (ce) - { - b2ContactEdge* ce0 = ce; - ce = ce->next; - m_world->m_contactManager.Destroy(ce0->contact); - } - m_contactList = NULL; - } -} - -void b2Body::Dump() -{ - int32 bodyIndex = m_islandIndex; - - b2Log("{\n"); - b2Log(" b2BodyDef bd;\n"); - b2Log(" bd.type = b2BodyType(%d);\n", m_type); - b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); - b2Log(" bd.angle = %.15lef;\n", m_sweep.a); - b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); - b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); - b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); - b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); - b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); - b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); - b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); - b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); - b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); - b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); - b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); - b2Log("\n"); - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) - { - b2Log(" {\n"); - f->Dump(bodyIndex); - b2Log(" }\n"); - } - b2Log("}\n"); -} \ No newline at end of file diff --git a/external/box2d/Dynamics/b2Body.h b/external/box2d/Dynamics/b2Body.h deleted file mode 100644 index e2d16bf630..0000000000 --- a/external/box2d/Dynamics/b2Body.h +++ /dev/null @@ -1,846 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_BODY_H -#define B2_BODY_H - -#include -#include -#include - -class b2Fixture; -class b2Joint; -class b2Contact; -class b2Controller; -class b2World; -struct b2FixtureDef; -struct b2JointEdge; -struct b2ContactEdge; - -/// The body type. -/// static: zero mass, zero velocity, may be manually moved -/// kinematic: zero mass, non-zero velocity set by user, moved by solver -/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver -enum b2BodyType -{ - b2_staticBody = 0, - b2_kinematicBody, - b2_dynamicBody - - // TODO_ERIN - //b2_bulletBody, -}; - -/// A body definition holds all the data needed to construct a rigid body. -/// You can safely re-use body definitions. Shapes are added to a body after construction. -struct b2BodyDef -{ - /// This constructor sets the body definition default values. - b2BodyDef() - { - userData = NULL; - position.Set(0.0f, 0.0f); - angle = 0.0f; - linearVelocity.Set(0.0f, 0.0f); - angularVelocity = 0.0f; - linearDamping = 0.0f; - angularDamping = 0.0f; - allowSleep = true; - awake = true; - fixedRotation = false; - bullet = false; - type = b2_staticBody; - active = true; - gravityScale = 1.0f; - } - - /// The body type: static, kinematic, or dynamic. - /// Note: if a dynamic body would have zero mass, the mass is set to one. - b2BodyType type; - - /// The world position of the body. Avoid creating bodies at the origin - /// since this can lead to many overlapping shapes. - b2Vec2 position; - - /// The world angle of the body in radians. - float32 angle; - - /// The linear velocity of the body's origin in world co-ordinates. - b2Vec2 linearVelocity; - - /// The angular velocity of the body. - float32 angularVelocity; - - /// Linear damping is use to reduce the linear velocity. The damping parameter - /// can be larger than 1.0f but the damping effect becomes sensitive to the - /// time step when the damping parameter is large. - float32 linearDamping; - - /// Angular damping is use to reduce the angular velocity. The damping parameter - /// can be larger than 1.0f but the damping effect becomes sensitive to the - /// time step when the damping parameter is large. - float32 angularDamping; - - /// Set this flag to false if this body should never fall asleep. Note that - /// this increases CPU usage. - bool allowSleep; - - /// Is this body initially awake or sleeping? - bool awake; - - /// Should this body be prevented from rotating? Useful for characters. - bool fixedRotation; - - /// Is this a fast moving body that should be prevented from tunneling through - /// other moving bodies? Note that all bodies are prevented from tunneling through - /// kinematic and static bodies. This setting is only considered on dynamic bodies. - /// @warning You should use this flag sparingly since it increases processing time. - bool bullet; - - /// Does this body start out active? - bool active; - - /// Use this to store application specific body data. - void* userData; - - /// Scale the gravity applied to this body. - float32 gravityScale; -}; - -/// A rigid body. These are created via b2World::CreateBody. -class b2Body -{ -public: - /// Creates a fixture and attach it to this body. Use this function if you need - /// to set some fixture parameters, like friction. Otherwise you can create the - /// fixture directly from a shape. - /// If the density is non-zero, this function automatically updates the mass of the body. - /// Contacts are not created until the next time step. - /// @param def the fixture definition. - /// @warning This function is locked during callbacks. - b2Fixture* CreateFixture(const b2FixtureDef* def); - - /// Creates a fixture from a shape and attach it to this body. - /// This is a convenience function. Use b2FixtureDef if you need to set parameters - /// like friction, restitution, user data, or filtering. - /// If the density is non-zero, this function automatically updates the mass of the body. - /// @param shape the shape to be cloned. - /// @param density the shape density (set to zero for static bodies). - /// @warning This function is locked during callbacks. - b2Fixture* CreateFixture(const b2Shape* shape, float32 density); - - /// Destroy a fixture. This removes the fixture from the broad-phase and - /// destroys all contacts associated with this fixture. This will - /// automatically adjust the mass of the body if the body is dynamic and the - /// fixture has positive density. - /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. - /// @param fixture the fixture to be removed. - /// @warning This function is locked during callbacks. - void DestroyFixture(b2Fixture* fixture); - - /// Set the position of the body's origin and rotation. - /// This breaks any contacts and wakes the other bodies. - /// Manipulating a body's transform may cause non-physical behavior. - /// @param position the world position of the body's local origin. - /// @param angle the world rotation in radians. - void SetTransform(const b2Vec2& position, float32 angle); - - /// Get the body transform for the body's origin. - /// @return the world transform of the body's origin. - const b2Transform& GetTransform() const; - - /// Get the world body origin position. - /// @return the world position of the body's origin. - const b2Vec2& GetPosition() const; - - /// Get the angle in radians. - /// @return the current world rotation angle in radians. - float32 GetAngle() const; - - /// Get the world position of the center of mass. - const b2Vec2& GetWorldCenter() const; - - /// Get the local position of the center of mass. - const b2Vec2& GetLocalCenter() const; - - /// Set the linear velocity of the center of mass. - /// @param v the new linear velocity of the center of mass. - void SetLinearVelocity(const b2Vec2& v); - - /// Get the linear velocity of the center of mass. - /// @return the linear velocity of the center of mass. - b2Vec2 GetLinearVelocity() const; - - /// Set the angular velocity. - /// @param omega the new angular velocity in radians/second. - void SetAngularVelocity(float32 omega); - - /// Get the angular velocity. - /// @return the angular velocity in radians/second. - float32 GetAngularVelocity() const; - - /// Apply a force at a world point. If the force is not - /// applied at the center of mass, it will generate a torque and - /// affect the angular velocity. This wakes up the body. - /// @param force the world force vector, usually in Newtons (N). - /// @param point the world position of the point of application. - void ApplyForce(const b2Vec2& force, const b2Vec2& point); - - /// Apply a force to the center of mass. This wakes up the body. - /// @param force the world force vector, usually in Newtons (N). - void ApplyForceToCenter(const b2Vec2& force); - - /// Apply a torque. This affects the angular velocity - /// without affecting the linear velocity of the center of mass. - /// This wakes up the body. - /// @param torque about the z-axis (out of the screen), usually in N-m. - void ApplyTorque(float32 torque); - - /// Apply an impulse at a point. This immediately modifies the velocity. - /// It also modifies the angular velocity if the point of application - /// is not at the center of mass. This wakes up the body. - /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. - /// @param point the world position of the point of application. - void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point); - - /// Apply an angular impulse. - /// @param impulse the angular impulse in units of kg*m*m/s - void ApplyAngularImpulse(float32 impulse); - - /// Get the total mass of the body. - /// @return the mass, usually in kilograms (kg). - float32 GetMass() const; - - /// Get the rotational inertia of the body about the local origin. - /// @return the rotational inertia, usually in kg-m^2. - float32 GetInertia() const; - - /// Get the mass data of the body. - /// @return a struct containing the mass, inertia and center of the body. - void GetMassData(b2MassData* data) const; - - /// Set the mass properties to override the mass properties of the fixtures. - /// Note that this changes the center of mass position. - /// Note that creating or destroying fixtures can also alter the mass. - /// This function has no effect if the body isn't dynamic. - /// @param massData the mass properties. - void SetMassData(const b2MassData* data); - - /// This resets the mass properties to the sum of the mass properties of the fixtures. - /// This normally does not need to be called unless you called SetMassData to override - /// the mass and you later want to reset the mass. - void ResetMassData(); - - /// Get the world coordinates of a point given the local coordinates. - /// @param localPoint a point on the body measured relative the the body's origin. - /// @return the same point expressed in world coordinates. - b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; - - /// Get the world coordinates of a vector given the local coordinates. - /// @param localVector a vector fixed in the body. - /// @return the same vector expressed in world coordinates. - b2Vec2 GetWorldVector(const b2Vec2& localVector) const; - - /// Gets a local point relative to the body's origin given a world point. - /// @param a point in world coordinates. - /// @return the corresponding local point relative to the body's origin. - b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; - - /// Gets a local vector given a world vector. - /// @param a vector in world coordinates. - /// @return the corresponding local vector. - b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; - - /// Get the world linear velocity of a world point attached to this body. - /// @param a point in world coordinates. - /// @return the world velocity of a point. - b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; - - /// Get the world velocity of a local point. - /// @param a point in local coordinates. - /// @return the world velocity of a point. - b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; - - /// Get the linear damping of the body. - float32 GetLinearDamping() const; - - /// Set the linear damping of the body. - void SetLinearDamping(float32 linearDamping); - - /// Get the angular damping of the body. - float32 GetAngularDamping() const; - - /// Set the angular damping of the body. - void SetAngularDamping(float32 angularDamping); - - /// Get the gravity scale of the body. - float32 GetGravityScale() const; - - /// Set the gravity scale of the body. - void SetGravityScale(float32 scale); - - /// Set the type of this body. This may alter the mass and velocity. - void SetType(b2BodyType type); - - /// Get the type of this body. - b2BodyType GetType() const; - - /// Should this body be treated like a bullet for continuous collision detection? - void SetBullet(bool flag); - - /// Is this body treated like a bullet for continuous collision detection? - bool IsBullet() const; - - /// You can disable sleeping on this body. If you disable sleeping, the - /// body will be woken. - void SetSleepingAllowed(bool flag); - - /// Is this body allowed to sleep - bool IsSleepingAllowed() const; - - /// Set the sleep state of the body. A sleeping body has very - /// low CPU cost. - /// @param flag set to true to put body to sleep, false to wake it. - void SetAwake(bool flag); - - /// Get the sleeping state of this body. - /// @return true if the body is sleeping. - bool IsAwake() const; - - /// Set the active state of the body. An inactive body is not - /// simulated and cannot be collided with or woken up. - /// If you pass a flag of true, all fixtures will be added to the - /// broad-phase. - /// If you pass a flag of false, all fixtures will be removed from - /// the broad-phase and all contacts will be destroyed. - /// Fixtures and joints are otherwise unaffected. You may continue - /// to create/destroy fixtures and joints on inactive bodies. - /// Fixtures on an inactive body are implicitly inactive and will - /// not participate in collisions, ray-casts, or queries. - /// Joints connected to an inactive body are implicitly inactive. - /// An inactive body is still owned by a b2World object and remains - /// in the body list. - void SetActive(bool flag); - - /// Get the active state of the body. - bool IsActive() const; - - /// Set this body to have fixed rotation. This causes the mass - /// to be reset. - void SetFixedRotation(bool flag); - - /// Does this body have fixed rotation? - bool IsFixedRotation() const; - - /// Get the list of all fixtures attached to this body. - b2Fixture* GetFixtureList(); - const b2Fixture* GetFixtureList() const; - - /// Get the list of all joints attached to this body. - b2JointEdge* GetJointList(); - const b2JointEdge* GetJointList() const; - - /// Get the list of all contacts attached to this body. - /// @warning this list changes during the time step and you may - /// miss some collisions if you don't use b2ContactListener. - b2ContactEdge* GetContactList(); - const b2ContactEdge* GetContactList() const; - - /// Get the next body in the world's body list. - b2Body* GetNext(); - const b2Body* GetNext() const; - - /// Get the user data pointer that was provided in the body definition. - void* GetUserData() const; - - /// Set the user data. Use this to store your application specific data. - void SetUserData(void* data); - - /// Get the parent world of this body. - b2World* GetWorld(); - const b2World* GetWorld() const; - - /// Dump this body to a log file - void Dump(); - -private: - - friend class b2World; - friend class b2Island; - friend class b2ContactManager; - friend class b2ContactSolver; - friend class b2Contact; - - friend class b2DistanceJoint; - friend class b2GearJoint; - friend class b2WheelJoint; - friend class b2MouseJoint; - friend class b2PrismaticJoint; - friend class b2PulleyJoint; - friend class b2RevoluteJoint; - friend class b2WeldJoint; - friend class b2FrictionJoint; - friend class b2RopeJoint; - - // m_flags - enum - { - e_islandFlag = 0x0001, - e_awakeFlag = 0x0002, - e_autoSleepFlag = 0x0004, - e_bulletFlag = 0x0008, - e_fixedRotationFlag = 0x0010, - e_activeFlag = 0x0020, - e_toiFlag = 0x0040 - }; - - b2Body(const b2BodyDef* bd, b2World* world); - ~b2Body(); - - void SynchronizeFixtures(); - void SynchronizeTransform(); - - // This is used to prevent connected bodies from colliding. - // It may lie, depending on the collideConnected flag. - bool ShouldCollide(const b2Body* other) const; - - void Advance(float32 t); - - b2BodyType m_type; - - uint16 m_flags; - - int32 m_islandIndex; - - b2Transform m_xf; // the body origin transform - b2Sweep m_sweep; // the swept motion for CCD - - b2Vec2 m_linearVelocity; - float32 m_angularVelocity; - - b2Vec2 m_force; - float32 m_torque; - - b2World* m_world; - b2Body* m_prev; - b2Body* m_next; - - b2Fixture* m_fixtureList; - int32 m_fixtureCount; - - b2JointEdge* m_jointList; - b2ContactEdge* m_contactList; - - float32 m_mass, m_invMass; - - // Rotational inertia about the center of mass. - float32 m_I, m_invI; - - float32 m_linearDamping; - float32 m_angularDamping; - float32 m_gravityScale; - - float32 m_sleepTime; - - void* m_userData; -}; - -inline b2BodyType b2Body::GetType() const -{ - return m_type; -} - -inline const b2Transform& b2Body::GetTransform() const -{ - return m_xf; -} - -inline const b2Vec2& b2Body::GetPosition() const -{ - return m_xf.p; -} - -inline float32 b2Body::GetAngle() const -{ - return m_sweep.a; -} - -inline const b2Vec2& b2Body::GetWorldCenter() const -{ - return m_sweep.c; -} - -inline const b2Vec2& b2Body::GetLocalCenter() const -{ - return m_sweep.localCenter; -} - -inline void b2Body::SetLinearVelocity(const b2Vec2& v) -{ - if (m_type == b2_staticBody) - { - return; - } - - if (b2Dot(v,v) > 0.0f) - { - SetAwake(true); - } - - m_linearVelocity = v; -} - -inline b2Vec2 b2Body::GetLinearVelocity() const -{ - return m_linearVelocity; -} - -inline void b2Body::SetAngularVelocity(float32 w) -{ - if (m_type == b2_staticBody) - { - return; - } - - if (w * w > 0.0f) - { - SetAwake(true); - } - - m_angularVelocity = w; -} - -inline float32 b2Body::GetAngularVelocity() const -{ - return m_angularVelocity; -} - -inline float32 b2Body::GetMass() const -{ - return m_mass; -} - -inline float32 b2Body::GetInertia() const -{ - return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); -} - -inline void b2Body::GetMassData(b2MassData* data) const -{ - data->mass = m_mass; - data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); - data->center = m_sweep.localCenter; -} - -inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const -{ - return b2Mul(m_xf, localPoint); -} - -inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const -{ - return b2Mul(m_xf.q, localVector); -} - -inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const -{ - return b2MulT(m_xf, worldPoint); -} - -inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const -{ - return b2MulT(m_xf.q, worldVector); -} - -inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const -{ - return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); -} - -inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const -{ - return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); -} - -inline float32 b2Body::GetLinearDamping() const -{ - return m_linearDamping; -} - -inline void b2Body::SetLinearDamping(float32 linearDamping) -{ - m_linearDamping = linearDamping; -} - -inline float32 b2Body::GetAngularDamping() const -{ - return m_angularDamping; -} - -inline void b2Body::SetAngularDamping(float32 angularDamping) -{ - m_angularDamping = angularDamping; -} - -inline float32 b2Body::GetGravityScale() const -{ - return m_gravityScale; -} - -inline void b2Body::SetGravityScale(float32 scale) -{ - m_gravityScale = scale; -} - -inline void b2Body::SetBullet(bool flag) -{ - if (flag) - { - m_flags |= e_bulletFlag; - } - else - { - m_flags &= ~e_bulletFlag; - } -} - -inline bool b2Body::IsBullet() const -{ - return (m_flags & e_bulletFlag) == e_bulletFlag; -} - -inline void b2Body::SetAwake(bool flag) -{ - if (flag) - { - if ((m_flags & e_awakeFlag) == 0) - { - m_flags |= e_awakeFlag; - m_sleepTime = 0.0f; - } - } - else - { - m_flags &= ~e_awakeFlag; - m_sleepTime = 0.0f; - m_linearVelocity.SetZero(); - m_angularVelocity = 0.0f; - m_force.SetZero(); - m_torque = 0.0f; - } -} - -inline bool b2Body::IsAwake() const -{ - return (m_flags & e_awakeFlag) == e_awakeFlag; -} - -inline bool b2Body::IsActive() const -{ - return (m_flags & e_activeFlag) == e_activeFlag; -} - -inline void b2Body::SetFixedRotation(bool flag) -{ - if (flag) - { - m_flags |= e_fixedRotationFlag; - } - else - { - m_flags &= ~e_fixedRotationFlag; - } - - ResetMassData(); -} - -inline bool b2Body::IsFixedRotation() const -{ - return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; -} - -inline void b2Body::SetSleepingAllowed(bool flag) -{ - if (flag) - { - m_flags |= e_autoSleepFlag; - } - else - { - m_flags &= ~e_autoSleepFlag; - SetAwake(true); - } -} - -inline bool b2Body::IsSleepingAllowed() const -{ - return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; -} - -inline b2Fixture* b2Body::GetFixtureList() -{ - return m_fixtureList; -} - -inline const b2Fixture* b2Body::GetFixtureList() const -{ - return m_fixtureList; -} - -inline b2JointEdge* b2Body::GetJointList() -{ - return m_jointList; -} - -inline const b2JointEdge* b2Body::GetJointList() const -{ - return m_jointList; -} - -inline b2ContactEdge* b2Body::GetContactList() -{ - return m_contactList; -} - -inline const b2ContactEdge* b2Body::GetContactList() const -{ - return m_contactList; -} - -inline b2Body* b2Body::GetNext() -{ - return m_next; -} - -inline const b2Body* b2Body::GetNext() const -{ - return m_next; -} - -inline void b2Body::SetUserData(void* data) -{ - m_userData = data; -} - -inline void* b2Body::GetUserData() const -{ - return m_userData; -} - -inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_force += force; - m_torque += b2Cross(point - m_sweep.c, force); -} - -inline void b2Body::ApplyForceToCenter(const b2Vec2& force) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_force += force; -} - -inline void b2Body::ApplyTorque(float32 torque) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - - m_torque += torque; -} - -inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - m_linearVelocity += m_invMass * impulse; - m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); -} - -inline void b2Body::ApplyAngularImpulse(float32 impulse) -{ - if (m_type != b2_dynamicBody) - { - return; - } - - if (IsAwake() == false) - { - SetAwake(true); - } - m_angularVelocity += m_invI * impulse; -} - -inline void b2Body::SynchronizeTransform() -{ - m_xf.q.Set(m_sweep.a); - m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); -} - -inline void b2Body::Advance(float32 alpha) -{ - // Advance to the new safe time. This doesn't sync the broad-phase. - m_sweep.Advance(alpha); - m_sweep.c = m_sweep.c0; - m_sweep.a = m_sweep.a0; - m_xf.q.Set(m_sweep.a); - m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); -} - -inline b2World* b2Body::GetWorld() -{ - return m_world; -} - -inline const b2World* b2Body::GetWorld() const -{ - return m_world; -} - -#endif diff --git a/external/box2d/Dynamics/b2ContactManager.cpp b/external/box2d/Dynamics/b2ContactManager.cpp deleted file mode 100644 index c14cc4ce45..0000000000 --- a/external/box2d/Dynamics/b2ContactManager.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include - -b2ContactFilter b2_defaultFilter; -b2ContactListener b2_defaultListener; - -b2ContactManager::b2ContactManager() -{ - m_contactList = NULL; - m_contactCount = 0; - m_contactFilter = &b2_defaultFilter; - m_contactListener = &b2_defaultListener; - m_allocator = NULL; -} - -void b2ContactManager::Destroy(b2Contact* c) -{ - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - if (m_contactListener && c->IsTouching()) - { - m_contactListener->EndContact(c); - } - - // Remove from the world. - if (c->m_prev) - { - c->m_prev->m_next = c->m_next; - } - - if (c->m_next) - { - c->m_next->m_prev = c->m_prev; - } - - if (c == m_contactList) - { - m_contactList = c->m_next; - } - - // Remove from body 1 - if (c->m_nodeA.prev) - { - c->m_nodeA.prev->next = c->m_nodeA.next; - } - - if (c->m_nodeA.next) - { - c->m_nodeA.next->prev = c->m_nodeA.prev; - } - - if (&c->m_nodeA == bodyA->m_contactList) - { - bodyA->m_contactList = c->m_nodeA.next; - } - - // Remove from body 2 - if (c->m_nodeB.prev) - { - c->m_nodeB.prev->next = c->m_nodeB.next; - } - - if (c->m_nodeB.next) - { - c->m_nodeB.next->prev = c->m_nodeB.prev; - } - - if (&c->m_nodeB == bodyB->m_contactList) - { - bodyB->m_contactList = c->m_nodeB.next; - } - - // Call the factory. - b2Contact::Destroy(c, m_allocator); - --m_contactCount; -} - -// This is the top level collision call for the time step. Here -// all the narrow phase collision is processed for the world -// contact list. -void b2ContactManager::Collide() -{ - // Update awake contacts. - b2Contact* c = m_contactList; - while (c) - { - b2Fixture* fixtureA = c->GetFixtureA(); - b2Fixture* fixtureB = c->GetFixtureB(); - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - // Is this contact flagged for filtering? - if (c->m_flags & b2Contact::e_filterFlag) - { - // Should these bodies collide? - if (bodyB->ShouldCollide(bodyA) == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // Check user filtering. - if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // Clear the filtering flag. - c->m_flags &= ~b2Contact::e_filterFlag; - } - - bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; - bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; - - // At least one body must be awake and it must be dynamic or kinematic. - if (activeA == false && activeB == false) - { - c = c->GetNext(); - continue; - } - - int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; - int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; - bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); - - // Here we destroy contacts that cease to overlap in the broad-phase. - if (overlap == false) - { - b2Contact* cNuke = c; - c = cNuke->GetNext(); - Destroy(cNuke); - continue; - } - - // The contact persists. - c->Update(m_contactListener); - c = c->GetNext(); - } -} - -void b2ContactManager::FindNewContacts() -{ - m_broadPhase.UpdatePairs(this); -} - -void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) -{ - b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; - b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; - - b2Fixture* fixtureA = proxyA->fixture; - b2Fixture* fixtureB = proxyB->fixture; - - int32 indexA = proxyA->childIndex; - int32 indexB = proxyB->childIndex; - - b2Body* bodyA = fixtureA->GetBody(); - b2Body* bodyB = fixtureB->GetBody(); - - // Are the fixtures on the same body? - if (bodyA == bodyB) - { - return; - } - - // TODO_ERIN use a hash table to remove a potential bottleneck when both - // bodies have a lot of contacts. - // Does a contact already exist? - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - b2Fixture* fA = edge->contact->GetFixtureA(); - b2Fixture* fB = edge->contact->GetFixtureB(); - int32 iA = edge->contact->GetChildIndexA(); - int32 iB = edge->contact->GetChildIndexB(); - - if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) - { - // A contact already exists. - return; - } - - if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) - { - // A contact already exists. - return; - } - } - - edge = edge->next; - } - - // Does a joint override collision? Is at least one body dynamic? - if (bodyB->ShouldCollide(bodyA) == false) - { - return; - } - - // Check user filtering. - if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) - { - return; - } - - // Call the factory. - b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); - if (c == NULL) - { - return; - } - - // Contact creation may swap fixtures. - fixtureA = c->GetFixtureA(); - fixtureB = c->GetFixtureB(); - indexA = c->GetChildIndexA(); - indexB = c->GetChildIndexB(); - bodyA = fixtureA->GetBody(); - bodyB = fixtureB->GetBody(); - - // Insert into the world. - c->m_prev = NULL; - c->m_next = m_contactList; - if (m_contactList != NULL) - { - m_contactList->m_prev = c; - } - m_contactList = c; - - // Connect to island graph. - - // Connect to body A - c->m_nodeA.contact = c; - c->m_nodeA.other = bodyB; - - c->m_nodeA.prev = NULL; - c->m_nodeA.next = bodyA->m_contactList; - if (bodyA->m_contactList != NULL) - { - bodyA->m_contactList->prev = &c->m_nodeA; - } - bodyA->m_contactList = &c->m_nodeA; - - // Connect to body B - c->m_nodeB.contact = c; - c->m_nodeB.other = bodyA; - - c->m_nodeB.prev = NULL; - c->m_nodeB.next = bodyB->m_contactList; - if (bodyB->m_contactList != NULL) - { - bodyB->m_contactList->prev = &c->m_nodeB; - } - bodyB->m_contactList = &c->m_nodeB; - - // Wake up the bodies - bodyA->SetAwake(true); - bodyB->SetAwake(true); - - ++m_contactCount; -} diff --git a/external/box2d/Dynamics/b2ContactManager.h b/external/box2d/Dynamics/b2ContactManager.h deleted file mode 100644 index 9cb5718145..0000000000 --- a/external/box2d/Dynamics/b2ContactManager.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_CONTACT_MANAGER_H -#define B2_CONTACT_MANAGER_H - -#include - -class b2Contact; -class b2ContactFilter; -class b2ContactListener; -class b2BlockAllocator; - -// Delegate of b2World. -class b2ContactManager -{ -public: - b2ContactManager(); - - // Broad-phase callback. - void AddPair(void* proxyUserDataA, void* proxyUserDataB); - - void FindNewContacts(); - - void Destroy(b2Contact* c); - - void Collide(); - - b2BroadPhase m_broadPhase; - b2Contact* m_contactList; - int32 m_contactCount; - b2ContactFilter* m_contactFilter; - b2ContactListener* m_contactListener; - b2BlockAllocator* m_allocator; -}; - -#endif diff --git a/external/box2d/Dynamics/b2Fixture.cpp b/external/box2d/Dynamics/b2Fixture.cpp deleted file mode 100644 index 774a78e5bb..0000000000 --- a/external/box2d/Dynamics/b2Fixture.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -b2Fixture::b2Fixture() -{ - m_userData = NULL; - m_body = NULL; - m_next = NULL; - m_proxies = NULL; - m_proxyCount = 0; - m_shape = NULL; - m_density = 0.0f; -} - -void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) -{ - m_userData = def->userData; - m_friction = def->friction; - m_restitution = def->restitution; - - m_body = body; - m_next = NULL; - - m_filter = def->filter; - - m_isSensor = def->isSensor; - - m_shape = def->shape->Clone(allocator); - - // Reserve proxy space - int32 childCount = m_shape->GetChildCount(); - m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); - for (int32 i = 0; i < childCount; ++i) - { - m_proxies[i].fixture = NULL; - m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; - } - m_proxyCount = 0; - - m_density = def->density; -} - -void b2Fixture::Destroy(b2BlockAllocator* allocator) -{ - // The proxies must be destroyed before calling this. - b2Assert(m_proxyCount == 0); - - // Free the proxy array. - int32 childCount = m_shape->GetChildCount(); - allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); - m_proxies = NULL; - - // Free the child shape. - switch (m_shape->m_type) - { - case b2Shape::e_circle: - { - b2CircleShape* s = (b2CircleShape*)m_shape; - s->~b2CircleShape(); - allocator->Free(s, sizeof(b2CircleShape)); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* s = (b2EdgeShape*)m_shape; - s->~b2EdgeShape(); - allocator->Free(s, sizeof(b2EdgeShape)); - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* s = (b2PolygonShape*)m_shape; - s->~b2PolygonShape(); - allocator->Free(s, sizeof(b2PolygonShape)); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* s = (b2ChainShape*)m_shape; - s->~b2ChainShape(); - allocator->Free(s, sizeof(b2ChainShape)); - } - break; - - default: - b2Assert(false); - break; - } - - m_shape = NULL; -} - -void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) -{ - b2Assert(m_proxyCount == 0); - - // Create proxies in the broad-phase. - m_proxyCount = m_shape->GetChildCount(); - - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - m_shape->ComputeAABB(&proxy->aabb, xf, i); - proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); - proxy->fixture = this; - proxy->childIndex = i; - } -} - -void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) -{ - // Destroy proxies in the broad-phase. - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - broadPhase->DestroyProxy(proxy->proxyId); - proxy->proxyId = b2BroadPhase::e_nullProxy; - } - - m_proxyCount = 0; -} - -void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) -{ - if (m_proxyCount == 0) - { - return; - } - - for (int32 i = 0; i < m_proxyCount; ++i) - { - b2FixtureProxy* proxy = m_proxies + i; - - // Compute an AABB that covers the swept shape (may miss some rotation effect). - b2AABB aabb1, aabb2; - m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); - m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); - - proxy->aabb.Combine(aabb1, aabb2); - - b2Vec2 displacement = transform2.p - transform1.p; - - broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); - } -} - -void b2Fixture::SetFilterData(const b2Filter& filter) -{ - m_filter = filter; - - Refilter(); -} - -void b2Fixture::Refilter() -{ - if (m_body == NULL) - { - return; - } - - // Flag associated contacts for filtering. - b2ContactEdge* edge = m_body->GetContactList(); - while (edge) - { - b2Contact* contact = edge->contact; - b2Fixture* fixtureA = contact->GetFixtureA(); - b2Fixture* fixtureB = contact->GetFixtureB(); - if (fixtureA == this || fixtureB == this) - { - contact->FlagForFiltering(); - } - - edge = edge->next; - } - - b2World* world = m_body->GetWorld(); - - if (world == NULL) - { - return; - } - - // Touch each proxy so that new pairs may be created - b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; - for (int32 i = 0; i < m_proxyCount; ++i) - { - broadPhase->TouchProxy(m_proxies[i].proxyId); - } -} - -void b2Fixture::SetSensor(bool sensor) -{ - if (sensor != m_isSensor) - { - m_body->SetAwake(true); - m_isSensor = sensor; - } -} - -void b2Fixture::Dump(int32 bodyIndex) -{ - b2Log(" b2FixtureDef fd;\n"); - b2Log(" fd.friction = %.15lef;\n", m_friction); - b2Log(" fd.restitution = %.15lef;\n", m_restitution); - b2Log(" fd.density = %.15lef;\n", m_density); - b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); - b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); - b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); - b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); - - switch (m_shape->m_type) - { - case b2Shape::e_circle: - { - b2CircleShape* s = (b2CircleShape*)m_shape; - b2Log(" b2CircleShape shape;\n"); - b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); - b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* s = (b2EdgeShape*)m_shape; - b2Log(" b2EdgeShape shape;\n"); - b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); - b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); - b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); - b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); - b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); - b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); - b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* s = (b2PolygonShape*)m_shape; - b2Log(" b2PolygonShape shape;\n"); - b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); - for (int32 i = 0; i < s->m_vertexCount; ++i) - { - b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); - } - b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* s = (b2ChainShape*)m_shape; - b2Log(" b2ChainShape shape;\n"); - b2Log(" b2Vec2 vs[%d];\n", s->m_count); - for (int32 i = 0; i < s->m_count; ++i) - { - b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); - } - b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); - b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); - b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); - b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); - b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); - } - break; - - default: - return; - } - - b2Log("\n"); - b2Log(" fd.shape = &shape;\n"); - b2Log("\n"); - b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); -} diff --git a/external/box2d/Dynamics/b2Fixture.h b/external/box2d/Dynamics/b2Fixture.h deleted file mode 100644 index d390410b93..0000000000 --- a/external/box2d/Dynamics/b2Fixture.h +++ /dev/null @@ -1,345 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_FIXTURE_H -#define B2_FIXTURE_H - -#include -#include -#include - -class b2BlockAllocator; -class b2Body; -class b2BroadPhase; -class b2Fixture; - -/// This holds contact filtering data. -struct b2Filter -{ - b2Filter() - { - categoryBits = 0x0001; - maskBits = 0xFFFF; - groupIndex = 0; - } - - /// The collision category bits. Normally you would just set one bit. - uint16 categoryBits; - - /// The collision mask bits. This states the categories that this - /// shape would accept for collision. - uint16 maskBits; - - /// Collision groups allow a certain group of objects to never collide (negative) - /// or always collide (positive). Zero means no collision group. Non-zero group - /// filtering always wins against the mask bits. - int16 groupIndex; -}; - -/// A fixture definition is used to create a fixture. This class defines an -/// abstract fixture definition. You can reuse fixture definitions safely. -struct b2FixtureDef -{ - /// The constructor sets the default fixture definition values. - b2FixtureDef() - { - shape = NULL; - userData = NULL; - friction = 0.2f; - restitution = 0.0f; - density = 0.0f; - isSensor = false; - } - - /// The shape, this must be set. The shape will be cloned, so you - /// can create the shape on the stack. - const b2Shape* shape; - - /// Use this to store application specific fixture data. - void* userData; - - /// The friction coefficient, usually in the range [0,1]. - float32 friction; - - /// The restitution (elasticity) usually in the range [0,1]. - float32 restitution; - - /// The density, usually in kg/m^2. - float32 density; - - /// A sensor shape collects contact information but never generates a collision - /// response. - bool isSensor; - - /// Contact filtering data. - b2Filter filter; -}; - -/// This proxy is used internally to connect fixtures to the broad-phase. -struct b2FixtureProxy -{ - b2AABB aabb; - b2Fixture* fixture; - int32 childIndex; - int32 proxyId; -}; - -/// A fixture is used to attach a shape to a body for collision detection. A fixture -/// inherits its transform from its parent. Fixtures hold additional non-geometric data -/// such as friction, collision filters, etc. -/// Fixtures are created via b2Body::CreateFixture. -/// @warning you cannot reuse fixtures. -class b2Fixture -{ -public: - /// Get the type of the child shape. You can use this to down cast to the concrete shape. - /// @return the shape type. - b2Shape::Type GetType() const; - - /// Get the child shape. You can modify the child shape, however you should not change the - /// number of vertices because this will crash some collision caching mechanisms. - /// Manipulating the shape may lead to non-physical behavior. - b2Shape* GetShape(); - const b2Shape* GetShape() const; - - /// Set if this fixture is a sensor. - void SetSensor(bool sensor); - - /// Is this fixture a sensor (non-solid)? - /// @return the true if the shape is a sensor. - bool IsSensor() const; - - /// Set the contact filtering data. This will not update contacts until the next time - /// step when either parent body is active and awake. - /// This automatically calls Refilter. - void SetFilterData(const b2Filter& filter); - - /// Get the contact filtering data. - const b2Filter& GetFilterData() const; - - /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. - void Refilter(); - - /// Get the parent body of this fixture. This is NULL if the fixture is not attached. - /// @return the parent body. - b2Body* GetBody(); - const b2Body* GetBody() const; - - /// Get the next fixture in the parent body's fixture list. - /// @return the next shape. - b2Fixture* GetNext(); - const b2Fixture* GetNext() const; - - /// Get the user data that was assigned in the fixture definition. Use this to - /// store your application specific data. - void* GetUserData() const; - - /// Set the user data. Use this to store your application specific data. - void SetUserData(void* data); - - /// Test a point for containment in this fixture. - /// @param p a point in world coordinates. - bool TestPoint(const b2Vec2& p) const; - - /// Cast a ray against this shape. - /// @param output the ray-cast results. - /// @param input the ray-cast input parameters. - bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; - - /// Get the mass data for this fixture. The mass data is based on the density and - /// the shape. The rotational inertia is about the shape's origin. This operation - /// may be expensive. - void GetMassData(b2MassData* massData) const; - - /// Set the density of this fixture. This will _not_ automatically adjust the mass - /// of the body. You must call b2Body::ResetMassData to update the body's mass. - void SetDensity(float32 density); - - /// Get the density of this fixture. - float32 GetDensity() const; - - /// Get the coefficient of friction. - float32 GetFriction() const; - - /// Set the coefficient of friction. This will _not_ change the friction of - /// existing contacts. - void SetFriction(float32 friction); - - /// Get the coefficient of restitution. - float32 GetRestitution() const; - - /// Set the coefficient of restitution. This will _not_ change the restitution of - /// existing contacts. - void SetRestitution(float32 restitution); - - /// Get the fixture's AABB. This AABB may be enlarge and/or stale. - /// If you need a more accurate AABB, compute it using the shape and - /// the body transform. - const b2AABB& GetAABB(int32 childIndex) const; - - /// Dump this fixture to the log file. - void Dump(int32 bodyIndex); - -protected: - - friend class b2Body; - friend class b2World; - friend class b2Contact; - friend class b2ContactManager; - - b2Fixture(); - - // We need separation create/destroy functions from the constructor/destructor because - // the destructor cannot access the allocator (no destructor arguments allowed by C++). - void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); - void Destroy(b2BlockAllocator* allocator); - - // These support body activation/deactivation. - void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); - void DestroyProxies(b2BroadPhase* broadPhase); - - void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); - - float32 m_density; - - b2Fixture* m_next; - b2Body* m_body; - - b2Shape* m_shape; - - float32 m_friction; - float32 m_restitution; - - b2FixtureProxy* m_proxies; - int32 m_proxyCount; - - b2Filter m_filter; - - bool m_isSensor; - - void* m_userData; -}; - -inline b2Shape::Type b2Fixture::GetType() const -{ - return m_shape->GetType(); -} - -inline b2Shape* b2Fixture::GetShape() -{ - return m_shape; -} - -inline const b2Shape* b2Fixture::GetShape() const -{ - return m_shape; -} - -inline bool b2Fixture::IsSensor() const -{ - return m_isSensor; -} - -inline const b2Filter& b2Fixture::GetFilterData() const -{ - return m_filter; -} - -inline void* b2Fixture::GetUserData() const -{ - return m_userData; -} - -inline void b2Fixture::SetUserData(void* data) -{ - m_userData = data; -} - -inline b2Body* b2Fixture::GetBody() -{ - return m_body; -} - -inline const b2Body* b2Fixture::GetBody() const -{ - return m_body; -} - -inline b2Fixture* b2Fixture::GetNext() -{ - return m_next; -} - -inline const b2Fixture* b2Fixture::GetNext() const -{ - return m_next; -} - -inline void b2Fixture::SetDensity(float32 density) -{ - b2Assert(b2IsValid(density) && density >= 0.0f); - m_density = density; -} - -inline float32 b2Fixture::GetDensity() const -{ - return m_density; -} - -inline float32 b2Fixture::GetFriction() const -{ - return m_friction; -} - -inline void b2Fixture::SetFriction(float32 friction) -{ - m_friction = friction; -} - -inline float32 b2Fixture::GetRestitution() const -{ - return m_restitution; -} - -inline void b2Fixture::SetRestitution(float32 restitution) -{ - m_restitution = restitution; -} - -inline bool b2Fixture::TestPoint(const b2Vec2& p) const -{ - return m_shape->TestPoint(m_body->GetTransform(), p); -} - -inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const -{ - return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); -} - -inline void b2Fixture::GetMassData(b2MassData* massData) const -{ - m_shape->ComputeMass(massData, m_density); -} - -inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const -{ - b2Assert(0 <= childIndex && childIndex < m_proxyCount); - return m_proxies[childIndex].aabb; -} - -#endif diff --git a/external/box2d/Dynamics/b2Island.cpp b/external/box2d/Dynamics/b2Island.cpp deleted file mode 100644 index e767d383d5..0000000000 --- a/external/box2d/Dynamics/b2Island.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -Position Correction Notes -========================= -I tried the several algorithms for position correction of the 2D revolute joint. -I looked at these systems: -- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. -- suspension bridge with 30 1m long planks of length 1m. -- multi-link chain with 30 1m long links. - -Here are the algorithms: - -Baumgarte - A fraction of the position error is added to the velocity error. There is no -separate position solver. - -Pseudo Velocities - After the velocity solver and position integration, -the position error, Jacobian, and effective mass are recomputed. Then -the velocity constraints are solved with pseudo velocities and a fraction -of the position error is added to the pseudo velocity error. The pseudo -velocities are initialized to zero and there is no warm-starting. After -the position solver, the pseudo velocities are added to the positions. -This is also called the First Order World method or the Position LCP method. - -Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the -position error is re-computed for each constraint and the positions are updated -after the constraint is solved. The radius vectors (aka Jacobians) are -re-computed too (otherwise the algorithm has horrible instability). The pseudo -velocity states are not needed because they are effectively zero at the beginning -of each iteration. Since we have the current position error, we allow the -iterations to terminate early if the error becomes smaller than b2_linearSlop. - -Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed -each time a constraint is solved. - -Here are the results: -Baumgarte - this is the cheapest algorithm but it has some stability problems, -especially with the bridge. The chain links separate easily close to the root -and they jitter as they struggle to pull together. This is one of the most common -methods in the field. The big drawback is that the position correction artificially -affects the momentum, thus leading to instabilities and false bounce. I used a -bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller -factor makes joints and contacts more spongy. - -Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is -stable. However, joints still separate with large angular velocities. Drag the -simple pendulum in a circle quickly and the joint will separate. The chain separates -easily and does not recover. I used a bias factor of 0.2. A larger value lead to -the bridge collapsing when a heavy cube drops on it. - -Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo -Velocities, but in other ways it is worse. The bridge and chain are much more -stable, but the simple pendulum goes unstable at high angular velocities. - -Full NGS - stable in all tests. The joints display good stiffness. The bridge -still sags, but this is better than infinite forces. - -Recommendations -Pseudo Velocities are not really worthwhile because the bridge and chain cannot -recover from joint separation. In other cases the benefit over Baumgarte is small. - -Modified NGS is not a robust method for the revolute joint due to the violent -instability seen in the simple pendulum. Perhaps it is viable with other constraint -types, especially scalar constraints where the effective mass is a scalar. - -This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities -and is very fast. I don't think we can escape Baumgarte, especially in highly -demanding cases where high constraint fidelity is not needed. - -Full NGS is robust and easy on the eyes. I recommend this as an option for -higher fidelity simulation and certainly for suspension bridges and long chains. -Full NGS might be a good choice for ragdolls, especially motorized ragdolls where -joint separation can be problematic. The number of NGS iterations can be reduced -for better performance without harming robustness much. - -Each joint in a can be handled differently in the position solver. So I recommend -a system where the user can select the algorithm on a per joint basis. I would -probably default to the slower Full NGS and let the user select the faster -Baumgarte method in performance critical scenarios. -*/ - -/* -Cache Performance - -The Box2D solvers are dominated by cache misses. Data structures are designed -to increase the number of cache hits. Much of misses are due to random access -to body data. The constraint structures are iterated over linearly, which leads -to few cache misses. - -The bodies are not accessed during iteration. Instead read only data, such as -the mass values are stored with the constraints. The mutable data are the constraint -impulses and the bodies velocities/positions. The impulses are held inside the -constraint structures. The body velocities/positions are held in compact, temporary -arrays to increase the number of cache hits. Linear and angular velocity are -stored in a single array since multiple arrays lead to multiple misses. -*/ - -/* -2D Rotation - -R = [cos(theta) -sin(theta)] - [sin(theta) cos(theta) ] - -thetaDot = omega - -Let q1 = cos(theta), q2 = sin(theta). -R = [q1 -q2] - [q2 q1] - -q1Dot = -thetaDot * q2 -q2Dot = thetaDot * q1 - -q1_new = q1_old - dt * w * q2 -q2_new = q2_old + dt * w * q1 -then normalize. - -This might be faster than computing sin+cos. -However, we can compute sin+cos of the same angle fast. -*/ - -b2Island::b2Island( - int32 bodyCapacity, - int32 contactCapacity, - int32 jointCapacity, - b2StackAllocator* allocator, - b2ContactListener* listener) -{ - m_bodyCapacity = bodyCapacity; - m_contactCapacity = contactCapacity; - m_jointCapacity = jointCapacity; - m_bodyCount = 0; - m_contactCount = 0; - m_jointCount = 0; - - m_allocator = allocator; - m_listener = listener; - - m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); - m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); - m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); - - m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); - m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); -} - -b2Island::~b2Island() -{ - // Warning: the order should reverse the constructor order. - m_allocator->Free(m_positions); - m_allocator->Free(m_velocities); - m_allocator->Free(m_joints); - m_allocator->Free(m_contacts); - m_allocator->Free(m_bodies); -} - -void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) -{ - b2Timer timer; - - float32 h = step.dt; - - // Integrate velocities and apply damping. Initialize the body state. - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - - b2Vec2 c = b->m_sweep.c; - float32 a = b->m_sweep.a; - b2Vec2 v = b->m_linearVelocity; - float32 w = b->m_angularVelocity; - - // Store positions for continuous collision. - b->m_sweep.c0 = b->m_sweep.c; - b->m_sweep.a0 = b->m_sweep.a; - - if (b->m_type == b2_dynamicBody) - { - // Integrate velocities. - v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); - w += h * b->m_invI * b->m_torque; - - // Apply damping. - // ODE: dv/dt + c * v = 0 - // Solution: v(t) = v0 * exp(-c * t) - // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) - // v2 = exp(-c * dt) * v1 - // Taylor expansion: - // v2 = (1.0f - c * dt) * v1 - v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); - w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); - } - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - } - - timer.Reset(); - - // Solver data - b2SolverData solverData; - solverData.step = step; - solverData.positions = m_positions; - solverData.velocities = m_velocities; - - // Initialize velocity constraints. - b2ContactSolverDef contactSolverDef; - contactSolverDef.step = step; - contactSolverDef.contacts = m_contacts; - contactSolverDef.count = m_contactCount; - contactSolverDef.positions = m_positions; - contactSolverDef.velocities = m_velocities; - contactSolverDef.allocator = m_allocator; - - b2ContactSolver contactSolver(&contactSolverDef); - contactSolver.InitializeVelocityConstraints(); - - if (step.warmStarting) - { - contactSolver.WarmStart(); - } - - for (int32 i = 0; i < m_jointCount; ++i) - { - m_joints[i]->InitVelocityConstraints(solverData); - } - - profile->solveInit = timer.GetMilliseconds(); - - // Solve velocity constraints - timer.Reset(); - for (int32 i = 0; i < step.velocityIterations; ++i) - { - for (int32 j = 0; j < m_jointCount; ++j) - { - m_joints[j]->SolveVelocityConstraints(solverData); - } - - contactSolver.SolveVelocityConstraints(); - } - - // Store impulses for warm starting - contactSolver.StoreImpulses(); - profile->solveVelocity = timer.GetMilliseconds(); - - // Integrate positions - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Vec2 c = m_positions[i].c; - float32 a = m_positions[i].a; - b2Vec2 v = m_velocities[i].v; - float32 w = m_velocities[i].w; - - // Check for large velocities - b2Vec2 translation = h * v; - if (b2Dot(translation, translation) > b2_maxTranslationSquared) - { - float32 ratio = b2_maxTranslation / translation.Length(); - v *= ratio; - } - - float32 rotation = h * w; - if (rotation * rotation > b2_maxRotationSquared) - { - float32 ratio = b2_maxRotation / b2Abs(rotation); - w *= ratio; - } - - // Integrate - c += h * v; - a += h * w; - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - } - - // Solve position constraints - timer.Reset(); - bool positionSolved = false; - for (int32 i = 0; i < step.positionIterations; ++i) - { - bool contactsOkay = contactSolver.SolvePositionConstraints(); - - bool jointsOkay = true; - for (int32 i = 0; i < m_jointCount; ++i) - { - bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); - jointsOkay = jointsOkay && jointOkay; - } - - if (contactsOkay && jointsOkay) - { - // Exit early if the position errors are small. - positionSolved = true; - break; - } - } - - // Copy state buffers back to the bodies - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* body = m_bodies[i]; - body->m_sweep.c = m_positions[i].c; - body->m_sweep.a = m_positions[i].a; - body->m_linearVelocity = m_velocities[i].v; - body->m_angularVelocity = m_velocities[i].w; - body->SynchronizeTransform(); - } - - profile->solvePosition = timer.GetMilliseconds(); - - Report(contactSolver.m_velocityConstraints); - - if (allowSleep) - { - float32 minSleepTime = b2_maxFloat; - - const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; - const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; - - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - if (b->GetType() == b2_staticBody) - { - continue; - } - - if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || - b->m_angularVelocity * b->m_angularVelocity > angTolSqr || - b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) - { - b->m_sleepTime = 0.0f; - minSleepTime = 0.0f; - } - else - { - b->m_sleepTime += h; - minSleepTime = b2Min(minSleepTime, b->m_sleepTime); - } - } - - if (minSleepTime >= b2_timeToSleep && positionSolved) - { - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - b->SetAwake(false); - } - } - } -} - -void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) -{ - b2Assert(toiIndexA < m_bodyCount); - b2Assert(toiIndexB < m_bodyCount); - - // Initialize the body state. - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Body* b = m_bodies[i]; - m_positions[i].c = b->m_sweep.c; - m_positions[i].a = b->m_sweep.a; - m_velocities[i].v = b->m_linearVelocity; - m_velocities[i].w = b->m_angularVelocity; - } - - b2ContactSolverDef contactSolverDef; - contactSolverDef.contacts = m_contacts; - contactSolverDef.count = m_contactCount; - contactSolverDef.allocator = m_allocator; - contactSolverDef.step = subStep; - contactSolverDef.positions = m_positions; - contactSolverDef.velocities = m_velocities; - b2ContactSolver contactSolver(&contactSolverDef); - - // Solve position constraints. - for (int32 i = 0; i < subStep.positionIterations; ++i) - { - bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); - if (contactsOkay) - { - break; - } - } - -#if 0 - // Is the new position really safe? - for (int32 i = 0; i < m_contactCount; ++i) - { - b2Contact* c = m_contacts[i]; - b2Fixture* fA = c->GetFixtureA(); - b2Fixture* fB = c->GetFixtureB(); - - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - - b2DistanceInput input; - input.proxyA.Set(fA->GetShape(), indexA); - input.proxyB.Set(fB->GetShape(), indexB); - input.transformA = bA->GetTransform(); - input.transformB = bB->GetTransform(); - input.useRadii = false; - - b2DistanceOutput output; - b2SimplexCache cache; - cache.count = 0; - b2Distance(&output, &cache, &input); - - if (output.distance == 0 || cache.count == 3) - { - cache.count += 0; - } - } -#endif - - // Leap of faith to new safe state. - m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; - m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; - m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; - m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; - - // No warm starting is needed for TOI events because warm - // starting impulses were applied in the discrete solver. - contactSolver.InitializeVelocityConstraints(); - - // Solve velocity constraints. - for (int32 i = 0; i < subStep.velocityIterations; ++i) - { - contactSolver.SolveVelocityConstraints(); - } - - // Don't store the TOI contact forces for warm starting - // because they can be quite large. - - float32 h = subStep.dt; - - // Integrate positions - for (int32 i = 0; i < m_bodyCount; ++i) - { - b2Vec2 c = m_positions[i].c; - float32 a = m_positions[i].a; - b2Vec2 v = m_velocities[i].v; - float32 w = m_velocities[i].w; - - // Check for large velocities - b2Vec2 translation = h * v; - if (b2Dot(translation, translation) > b2_maxTranslationSquared) - { - float32 ratio = b2_maxTranslation / translation.Length(); - v *= ratio; - } - - float32 rotation = h * w; - if (rotation * rotation > b2_maxRotationSquared) - { - float32 ratio = b2_maxRotation / b2Abs(rotation); - w *= ratio; - } - - // Integrate - c += h * v; - a += h * w; - - m_positions[i].c = c; - m_positions[i].a = a; - m_velocities[i].v = v; - m_velocities[i].w = w; - - // Sync bodies - b2Body* body = m_bodies[i]; - body->m_sweep.c = c; - body->m_sweep.a = a; - body->m_linearVelocity = v; - body->m_angularVelocity = w; - body->SynchronizeTransform(); - } - - Report(contactSolver.m_velocityConstraints); -} - -void b2Island::Report(const b2ContactVelocityConstraint* constraints) -{ - if (m_listener == NULL) - { - return; - } - - for (int32 i = 0; i < m_contactCount; ++i) - { - b2Contact* c = m_contacts[i]; - - const b2ContactVelocityConstraint* vc = constraints + i; - - b2ContactImpulse impulse; - impulse.count = vc->pointCount; - for (int32 j = 0; j < vc->pointCount; ++j) - { - impulse.normalImpulses[j] = vc->points[j].normalImpulse; - impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; - } - - m_listener->PostSolve(c, &impulse); - } -} diff --git a/external/box2d/Dynamics/b2Island.h b/external/box2d/Dynamics/b2Island.h deleted file mode 100644 index e0a6e41fc3..0000000000 --- a/external/box2d/Dynamics/b2Island.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_ISLAND_H -#define B2_ISLAND_H - -#include -#include -#include - -class b2Contact; -class b2Joint; -class b2StackAllocator; -class b2ContactListener; -struct b2ContactVelocityConstraint; -struct b2Profile; - -/// This is an internal class. -class b2Island -{ -public: - b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, - b2StackAllocator* allocator, b2ContactListener* listener); - ~b2Island(); - - void Clear() - { - m_bodyCount = 0; - m_contactCount = 0; - m_jointCount = 0; - } - - void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); - - void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); - - void Add(b2Body* body) - { - b2Assert(m_bodyCount < m_bodyCapacity); - body->m_islandIndex = m_bodyCount; - m_bodies[m_bodyCount] = body; - ++m_bodyCount; - } - - void Add(b2Contact* contact) - { - b2Assert(m_contactCount < m_contactCapacity); - m_contacts[m_contactCount++] = contact; - } - - void Add(b2Joint* joint) - { - b2Assert(m_jointCount < m_jointCapacity); - m_joints[m_jointCount++] = joint; - } - - void Report(const b2ContactVelocityConstraint* constraints); - - b2StackAllocator* m_allocator; - b2ContactListener* m_listener; - - b2Body** m_bodies; - b2Contact** m_contacts; - b2Joint** m_joints; - - b2Position* m_positions; - b2Velocity* m_velocities; - - int32 m_bodyCount; - int32 m_jointCount; - int32 m_contactCount; - - int32 m_bodyCapacity; - int32 m_contactCapacity; - int32 m_jointCapacity; -}; - -#endif diff --git a/external/box2d/Dynamics/b2TimeStep.h b/external/box2d/Dynamics/b2TimeStep.h deleted file mode 100644 index 30d723fcc3..0000000000 --- a/external/box2d/Dynamics/b2TimeStep.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_TIME_STEP_H -#define B2_TIME_STEP_H - -#include - -/// Profiling data. Times are in milliseconds. -struct b2Profile -{ - float32 step; - float32 collide; - float32 solve; - float32 solveInit; - float32 solveVelocity; - float32 solvePosition; - float32 broadphase; - float32 solveTOI; -}; - -/// This is an internal structure. -struct b2TimeStep -{ - float32 dt; // time step - float32 inv_dt; // inverse time step (0 if dt == 0). - float32 dtRatio; // dt * inv_dt0 - int32 velocityIterations; - int32 positionIterations; - bool warmStarting; -}; - -/// This is an internal structure. -struct b2Position -{ - b2Vec2 c; - float32 a; -}; - -/// This is an internal structure. -struct b2Velocity -{ - b2Vec2 v; - float32 w; -}; - -/// Solver Data -struct b2SolverData -{ - b2TimeStep step; - b2Position* positions; - b2Velocity* velocities; -}; - -#endif diff --git a/external/box2d/Dynamics/b2World.cpp b/external/box2d/Dynamics/b2World.cpp deleted file mode 100644 index 8a0aff5114..0000000000 --- a/external/box2d/Dynamics/b2World.cpp +++ /dev/null @@ -1,1316 +0,0 @@ -/* -* Copyright (c) 2006-2011 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -b2World::b2World(const b2Vec2& gravity) -{ - m_destructionListener = NULL; - m_debugDraw = NULL; - - m_bodyList = NULL; - m_jointList = NULL; - - m_bodyCount = 0; - m_jointCount = 0; - - m_warmStarting = true; - m_continuousPhysics = true; - m_subStepping = false; - - m_stepComplete = true; - - m_allowSleep = true; - m_gravity = gravity; - - m_flags = e_clearForces; - - m_inv_dt0 = 0.0f; - - m_contactManager.m_allocator = &m_blockAllocator; - - memset(&m_profile, 0, sizeof(b2Profile)); -} - -b2World::~b2World() -{ - // Some shapes allocate using b2Alloc. - b2Body* b = m_bodyList; - while (b) - { - b2Body* bNext = b->m_next; - - b2Fixture* f = b->m_fixtureList; - while (f) - { - b2Fixture* fNext = f->m_next; - f->m_proxyCount = 0; - f->Destroy(&m_blockAllocator); - f = fNext; - } - - b = bNext; - } -} - -void b2World::SetDestructionListener(b2DestructionListener* listener) -{ - m_destructionListener = listener; -} - -void b2World::SetContactFilter(b2ContactFilter* filter) -{ - m_contactManager.m_contactFilter = filter; -} - -void b2World::SetContactListener(b2ContactListener* listener) -{ - m_contactManager.m_contactListener = listener; -} - -void b2World::SetDebugDraw(b2Draw* debugDraw) -{ - m_debugDraw = debugDraw; -} - -b2Body* b2World::CreateBody(const b2BodyDef* def) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return NULL; - } - - void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); - b2Body* b = new (mem) b2Body(def, this); - - // Add to world doubly linked list. - b->m_prev = NULL; - b->m_next = m_bodyList; - if (m_bodyList) - { - m_bodyList->m_prev = b; - } - m_bodyList = b; - ++m_bodyCount; - - return b; -} - -void b2World::DestroyBody(b2Body* b) -{ - b2Assert(m_bodyCount > 0); - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return; - } - - // Delete the attached joints. - b2JointEdge* je = b->m_jointList; - while (je) - { - b2JointEdge* je0 = je; - je = je->next; - - if (m_destructionListener) - { - m_destructionListener->SayGoodbye(je0->joint); - } - - DestroyJoint(je0->joint); - - b->m_jointList = je; - } - b->m_jointList = NULL; - - // Delete the attached contacts. - b2ContactEdge* ce = b->m_contactList; - while (ce) - { - b2ContactEdge* ce0 = ce; - ce = ce->next; - m_contactManager.Destroy(ce0->contact); - } - b->m_contactList = NULL; - - // Delete the attached fixtures. This destroys broad-phase proxies. - b2Fixture* f = b->m_fixtureList; - while (f) - { - b2Fixture* f0 = f; - f = f->m_next; - - if (m_destructionListener) - { - m_destructionListener->SayGoodbye(f0); - } - - f0->DestroyProxies(&m_contactManager.m_broadPhase); - f0->Destroy(&m_blockAllocator); - f0->~b2Fixture(); - m_blockAllocator.Free(f0, sizeof(b2Fixture)); - - b->m_fixtureList = f; - b->m_fixtureCount -= 1; - } - b->m_fixtureList = NULL; - b->m_fixtureCount = 0; - - // Remove world body list. - if (b->m_prev) - { - b->m_prev->m_next = b->m_next; - } - - if (b->m_next) - { - b->m_next->m_prev = b->m_prev; - } - - if (b == m_bodyList) - { - m_bodyList = b->m_next; - } - - --m_bodyCount; - b->~b2Body(); - m_blockAllocator.Free(b, sizeof(b2Body)); -} - -b2Joint* b2World::CreateJoint(const b2JointDef* def) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return NULL; - } - - b2Joint* j = b2Joint::Create(def, &m_blockAllocator); - - // Connect to the world list. - j->m_prev = NULL; - j->m_next = m_jointList; - if (m_jointList) - { - m_jointList->m_prev = j; - } - m_jointList = j; - ++m_jointCount; - - // Connect to the bodies' doubly linked lists. - j->m_edgeA.joint = j; - j->m_edgeA.other = j->m_bodyB; - j->m_edgeA.prev = NULL; - j->m_edgeA.next = j->m_bodyA->m_jointList; - if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; - j->m_bodyA->m_jointList = &j->m_edgeA; - - j->m_edgeB.joint = j; - j->m_edgeB.other = j->m_bodyA; - j->m_edgeB.prev = NULL; - j->m_edgeB.next = j->m_bodyB->m_jointList; - if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; - j->m_bodyB->m_jointList = &j->m_edgeB; - - b2Body* bodyA = def->bodyA; - b2Body* bodyB = def->bodyB; - - // If the joint prevents collisions, then flag any contacts for filtering. - if (def->collideConnected == false) - { - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - // Flag the contact for filtering at the next time step (where either - // body is awake). - edge->contact->FlagForFiltering(); - } - - edge = edge->next; - } - } - - // Note: creating a joint doesn't wake the bodies. - - return j; -} - -void b2World::DestroyJoint(b2Joint* j) -{ - b2Assert(IsLocked() == false); - if (IsLocked()) - { - return; - } - - bool collideConnected = j->m_collideConnected; - - // Remove from the doubly linked list. - if (j->m_prev) - { - j->m_prev->m_next = j->m_next; - } - - if (j->m_next) - { - j->m_next->m_prev = j->m_prev; - } - - if (j == m_jointList) - { - m_jointList = j->m_next; - } - - // Disconnect from island graph. - b2Body* bodyA = j->m_bodyA; - b2Body* bodyB = j->m_bodyB; - - // Wake up connected bodies. - bodyA->SetAwake(true); - bodyB->SetAwake(true); - - // Remove from body 1. - if (j->m_edgeA.prev) - { - j->m_edgeA.prev->next = j->m_edgeA.next; - } - - if (j->m_edgeA.next) - { - j->m_edgeA.next->prev = j->m_edgeA.prev; - } - - if (&j->m_edgeA == bodyA->m_jointList) - { - bodyA->m_jointList = j->m_edgeA.next; - } - - j->m_edgeA.prev = NULL; - j->m_edgeA.next = NULL; - - // Remove from body 2 - if (j->m_edgeB.prev) - { - j->m_edgeB.prev->next = j->m_edgeB.next; - } - - if (j->m_edgeB.next) - { - j->m_edgeB.next->prev = j->m_edgeB.prev; - } - - if (&j->m_edgeB == bodyB->m_jointList) - { - bodyB->m_jointList = j->m_edgeB.next; - } - - j->m_edgeB.prev = NULL; - j->m_edgeB.next = NULL; - - b2Joint::Destroy(j, &m_blockAllocator); - - b2Assert(m_jointCount > 0); - --m_jointCount; - - // If the joint prevents collisions, then flag any contacts for filtering. - if (collideConnected == false) - { - b2ContactEdge* edge = bodyB->GetContactList(); - while (edge) - { - if (edge->other == bodyA) - { - // Flag the contact for filtering at the next time step (where either - // body is awake). - edge->contact->FlagForFiltering(); - } - - edge = edge->next; - } - } -} - -// -void b2World::SetAllowSleeping(bool flag) -{ - if (flag == m_allowSleep) - { - return; - } - - m_allowSleep = flag; - if (m_allowSleep == false) - { - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->SetAwake(true); - } - } -} - -// Find islands, integrate and solve constraints, solve position constraints -void b2World::Solve(const b2TimeStep& step) -{ - m_profile.solveInit = 0.0f; - m_profile.solveVelocity = 0.0f; - m_profile.solvePosition = 0.0f; - - // Size the island for the worst case. - b2Island island(m_bodyCount, - m_contactManager.m_contactCount, - m_jointCount, - &m_stackAllocator, - m_contactManager.m_contactListener); - - // Clear all the island flags. - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_flags &= ~b2Body::e_islandFlag; - } - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - c->m_flags &= ~b2Contact::e_islandFlag; - } - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - j->m_islandFlag = false; - } - - // Build and simulate all awake islands. - int32 stackSize = m_bodyCount; - b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); - for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) - { - if (seed->m_flags & b2Body::e_islandFlag) - { - continue; - } - - if (seed->IsAwake() == false || seed->IsActive() == false) - { - continue; - } - - // The seed can be dynamic or kinematic. - if (seed->GetType() == b2_staticBody) - { - continue; - } - - // Reset island and stack. - island.Clear(); - int32 stackCount = 0; - stack[stackCount++] = seed; - seed->m_flags |= b2Body::e_islandFlag; - - // Perform a depth first search (DFS) on the constraint graph. - while (stackCount > 0) - { - // Grab the next body off the stack and add it to the island. - b2Body* b = stack[--stackCount]; - b2Assert(b->IsActive() == true); - island.Add(b); - - // Make sure the body is awake. - b->SetAwake(true); - - // To keep islands as small as possible, we don't - // propagate islands across static bodies. - if (b->GetType() == b2_staticBody) - { - continue; - } - - // Search all contacts connected to this body. - for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) - { - b2Contact* contact = ce->contact; - - // Has this contact already been added to an island? - if (contact->m_flags & b2Contact::e_islandFlag) - { - continue; - } - - // Is this contact solid and touching? - if (contact->IsEnabled() == false || - contact->IsTouching() == false) - { - continue; - } - - // Skip sensors. - bool sensorA = contact->m_fixtureA->m_isSensor; - bool sensorB = contact->m_fixtureB->m_isSensor; - if (sensorA || sensorB) - { - continue; - } - - island.Add(contact); - contact->m_flags |= b2Contact::e_islandFlag; - - b2Body* other = ce->other; - - // Was the other body already added to this island? - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - b2Assert(stackCount < stackSize); - stack[stackCount++] = other; - other->m_flags |= b2Body::e_islandFlag; - } - - // Search all joints connect to this body. - for (b2JointEdge* je = b->m_jointList; je; je = je->next) - { - if (je->joint->m_islandFlag == true) - { - continue; - } - - b2Body* other = je->other; - - // Don't simulate joints connected to inactive bodies. - if (other->IsActive() == false) - { - continue; - } - - island.Add(je->joint); - je->joint->m_islandFlag = true; - - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - b2Assert(stackCount < stackSize); - stack[stackCount++] = other; - other->m_flags |= b2Body::e_islandFlag; - } - } - - b2Profile profile; - island.Solve(&profile, step, m_gravity, m_allowSleep); - m_profile.solveInit += profile.solveInit; - m_profile.solveVelocity += profile.solveVelocity; - m_profile.solvePosition += profile.solvePosition; - - // Post solve cleanup. - for (int32 i = 0; i < island.m_bodyCount; ++i) - { - // Allow static bodies to participate in other islands. - b2Body* b = island.m_bodies[i]; - if (b->GetType() == b2_staticBody) - { - b->m_flags &= ~b2Body::e_islandFlag; - } - } - } - - m_stackAllocator.Free(stack); - - { - b2Timer timer; - // Synchronize fixtures, check for out of range bodies. - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - // If a body was not in an island then it did not move. - if ((b->m_flags & b2Body::e_islandFlag) == 0) - { - continue; - } - - if (b->GetType() == b2_staticBody) - { - continue; - } - - // Update fixtures (for broad-phase). - b->SynchronizeFixtures(); - } - - // Look for new contacts. - m_contactManager.FindNewContacts(); - m_profile.broadphase = timer.GetMilliseconds(); - } -} - -// Find TOI contacts and solve them. -void b2World::SolveTOI(const b2TimeStep& step) -{ - b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); - - if (m_stepComplete) - { - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_flags &= ~b2Body::e_islandFlag; - b->m_sweep.alpha0 = 0.0f; - } - - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - // Invalidate TOI - c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); - c->m_toiCount = 0; - c->m_toi = 1.0f; - } - } - - // Find TOI events and solve them. - for (;;) - { - // Find the first TOI. - b2Contact* minContact = NULL; - float32 minAlpha = 1.0f; - - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) - { - // Is this contact disabled? - if (c->IsEnabled() == false) - { - continue; - } - - // Prevent excessive sub-stepping. - if (c->m_toiCount > b2_maxSubSteps) - { - continue; - } - - float32 alpha = 1.0f; - if (c->m_flags & b2Contact::e_toiFlag) - { - // This contact has a valid cached TOI. - alpha = c->m_toi; - } - else - { - b2Fixture* fA = c->GetFixtureA(); - b2Fixture* fB = c->GetFixtureB(); - - // Is there a sensor? - if (fA->IsSensor() || fB->IsSensor()) - { - continue; - } - - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - b2BodyType typeA = bA->m_type; - b2BodyType typeB = bB->m_type; - b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); - - bool activeA = bA->IsAwake() && typeA != b2_staticBody; - bool activeB = bB->IsAwake() && typeB != b2_staticBody; - - // Is at least one body active (awake and dynamic or kinematic)? - if (activeA == false && activeB == false) - { - continue; - } - - bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; - bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; - - // Are these two non-bullet dynamic bodies? - if (collideA == false && collideB == false) - { - continue; - } - - // Compute the TOI for this contact. - // Put the sweeps onto the same time interval. - float32 alpha0 = bA->m_sweep.alpha0; - - if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) - { - alpha0 = bB->m_sweep.alpha0; - bA->m_sweep.Advance(alpha0); - } - else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) - { - alpha0 = bA->m_sweep.alpha0; - bB->m_sweep.Advance(alpha0); - } - - b2Assert(alpha0 < 1.0f); - - int32 indexA = c->GetChildIndexA(); - int32 indexB = c->GetChildIndexB(); - - // Compute the time of impact in interval [0, minTOI] - b2TOIInput input; - input.proxyA.Set(fA->GetShape(), indexA); - input.proxyB.Set(fB->GetShape(), indexB); - input.sweepA = bA->m_sweep; - input.sweepB = bB->m_sweep; - input.tMax = 1.0f; - - b2TOIOutput output; - b2TimeOfImpact(&output, &input); - - // Beta is the fraction of the remaining portion of the . - float32 beta = output.t; - if (output.state == b2TOIOutput::e_touching) - { - alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); - } - else - { - alpha = 1.0f; - } - - c->m_toi = alpha; - c->m_flags |= b2Contact::e_toiFlag; - } - - if (alpha < minAlpha) - { - // This is the minimum TOI found so far. - minContact = c; - minAlpha = alpha; - } - } - - if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) - { - // No more TOI events. Done! - m_stepComplete = true; - break; - } - - // Advance the bodies to the TOI. - b2Fixture* fA = minContact->GetFixtureA(); - b2Fixture* fB = minContact->GetFixtureB(); - b2Body* bA = fA->GetBody(); - b2Body* bB = fB->GetBody(); - - b2Sweep backup1 = bA->m_sweep; - b2Sweep backup2 = bB->m_sweep; - - bA->Advance(minAlpha); - bB->Advance(minAlpha); - - // The TOI contact likely has some new contact points. - minContact->Update(m_contactManager.m_contactListener); - minContact->m_flags &= ~b2Contact::e_toiFlag; - ++minContact->m_toiCount; - - // Is the contact solid? - if (minContact->IsEnabled() == false || minContact->IsTouching() == false) - { - // Restore the sweeps. - minContact->SetEnabled(false); - bA->m_sweep = backup1; - bB->m_sweep = backup2; - bA->SynchronizeTransform(); - bB->SynchronizeTransform(); - continue; - } - - bA->SetAwake(true); - bB->SetAwake(true); - - // Build the island - island.Clear(); - island.Add(bA); - island.Add(bB); - island.Add(minContact); - - bA->m_flags |= b2Body::e_islandFlag; - bB->m_flags |= b2Body::e_islandFlag; - minContact->m_flags |= b2Contact::e_islandFlag; - - // Get contacts on bodyA and bodyB. - b2Body* bodies[2] = {bA, bB}; - for (int32 i = 0; i < 2; ++i) - { - b2Body* body = bodies[i]; - if (body->m_type == b2_dynamicBody) - { - for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) - { - if (island.m_bodyCount == island.m_bodyCapacity) - { - break; - } - - if (island.m_contactCount == island.m_contactCapacity) - { - break; - } - - b2Contact* contact = ce->contact; - - // Has this contact already been added to the island? - if (contact->m_flags & b2Contact::e_islandFlag) - { - continue; - } - - // Only add static, kinematic, or bullet bodies. - b2Body* other = ce->other; - if (other->m_type == b2_dynamicBody && - body->IsBullet() == false && other->IsBullet() == false) - { - continue; - } - - // Skip sensors. - bool sensorA = contact->m_fixtureA->m_isSensor; - bool sensorB = contact->m_fixtureB->m_isSensor; - if (sensorA || sensorB) - { - continue; - } - - // Tentatively advance the body to the TOI. - b2Sweep backup = other->m_sweep; - if ((other->m_flags & b2Body::e_islandFlag) == 0) - { - other->Advance(minAlpha); - } - - // Update the contact points - contact->Update(m_contactManager.m_contactListener); - - // Was the contact disabled by the user? - if (contact->IsEnabled() == false) - { - other->m_sweep = backup; - other->SynchronizeTransform(); - continue; - } - - // Are there contact points? - if (contact->IsTouching() == false) - { - other->m_sweep = backup; - other->SynchronizeTransform(); - continue; - } - - // Add the contact to the island - contact->m_flags |= b2Contact::e_islandFlag; - island.Add(contact); - - // Has the other body already been added to the island? - if (other->m_flags & b2Body::e_islandFlag) - { - continue; - } - - // Add the other body to the island. - other->m_flags |= b2Body::e_islandFlag; - - if (other->m_type != b2_staticBody) - { - other->SetAwake(true); - } - - island.Add(other); - } - } - } - - b2TimeStep subStep; - subStep.dt = (1.0f - minAlpha) * step.dt; - subStep.inv_dt = 1.0f / subStep.dt; - subStep.dtRatio = 1.0f; - subStep.positionIterations = 20; - subStep.velocityIterations = step.velocityIterations; - subStep.warmStarting = false; - island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); - - // Reset island flags and synchronize broad-phase proxies. - for (int32 i = 0; i < island.m_bodyCount; ++i) - { - b2Body* body = island.m_bodies[i]; - body->m_flags &= ~b2Body::e_islandFlag; - - if (body->m_type != b2_dynamicBody) - { - continue; - } - - body->SynchronizeFixtures(); - - // Invalidate all contact TOIs on this displaced body. - for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) - { - ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); - } - } - - // Commit fixture proxy movements to the broad-phase so that new contacts are created. - // Also, some contacts can be destroyed. - m_contactManager.FindNewContacts(); - - if (m_subStepping) - { - m_stepComplete = false; - break; - } - } -} - -void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) -{ - b2Timer stepTimer; - - // If new fixtures were added, we need to find the new contacts. - if (m_flags & e_newFixture) - { - m_contactManager.FindNewContacts(); - m_flags &= ~e_newFixture; - } - - m_flags |= e_locked; - - b2TimeStep step; - step.dt = dt; - step.velocityIterations = velocityIterations; - step.positionIterations = positionIterations; - if (dt > 0.0f) - { - step.inv_dt = 1.0f / dt; - } - else - { - step.inv_dt = 0.0f; - } - - step.dtRatio = m_inv_dt0 * dt; - - step.warmStarting = m_warmStarting; - - // Update contacts. This is where some contacts are destroyed. - { - b2Timer timer; - m_contactManager.Collide(); - m_profile.collide = timer.GetMilliseconds(); - } - - // Integrate velocities, solve velocity constraints, and integrate positions. - if (m_stepComplete && step.dt > 0.0f) - { - b2Timer timer; - Solve(step); - m_profile.solve = timer.GetMilliseconds(); - } - - // Handle TOI events. - if (m_continuousPhysics && step.dt > 0.0f) - { - b2Timer timer; - SolveTOI(step); - m_profile.solveTOI = timer.GetMilliseconds(); - } - - if (step.dt > 0.0f) - { - m_inv_dt0 = step.inv_dt; - } - - if (m_flags & e_clearForces) - { - ClearForces(); - } - - m_flags &= ~e_locked; - - m_profile.step = stepTimer.GetMilliseconds(); -} - -void b2World::ClearForces() -{ - for (b2Body* body = m_bodyList; body; body = body->GetNext()) - { - body->m_force.SetZero(); - body->m_torque = 0.0f; - } -} - -struct b2WorldQueryWrapper -{ - bool QueryCallback(int32 proxyId) - { - b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); - return callback->ReportFixture(proxy->fixture); - } - - const b2BroadPhase* broadPhase; - b2QueryCallback* callback; -}; - -void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const -{ - b2WorldQueryWrapper wrapper; - wrapper.broadPhase = &m_contactManager.m_broadPhase; - wrapper.callback = callback; - m_contactManager.m_broadPhase.Query(&wrapper, aabb); -} - -struct b2WorldRayCastWrapper -{ - float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) - { - void* userData = broadPhase->GetUserData(proxyId); - b2FixtureProxy* proxy = (b2FixtureProxy*)userData; - b2Fixture* fixture = proxy->fixture; - int32 index = proxy->childIndex; - b2RayCastOutput output; - bool hit = fixture->RayCast(&output, input, index); - - if (hit) - { - float32 fraction = output.fraction; - b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; - return callback->ReportFixture(fixture, point, output.normal, fraction); - } - - return input.maxFraction; - } - - const b2BroadPhase* broadPhase; - b2RayCastCallback* callback; -}; - -void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const -{ - b2WorldRayCastWrapper wrapper; - wrapper.broadPhase = &m_contactManager.m_broadPhase; - wrapper.callback = callback; - b2RayCastInput input; - input.maxFraction = 1.0f; - input.p1 = point1; - input.p2 = point2; - m_contactManager.m_broadPhase.RayCast(&wrapper, input); -} - -void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) -{ - switch (fixture->GetType()) - { - case b2Shape::e_circle: - { - b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); - - b2Vec2 center = b2Mul(xf, circle->m_p); - float32 radius = circle->m_radius; - b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); - - m_debugDraw->DrawSolidCircle(center, radius, axis, color); - } - break; - - case b2Shape::e_edge: - { - b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); - b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); - b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); - m_debugDraw->DrawSegment(v1, v2, color); - } - break; - - case b2Shape::e_chain: - { - b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); - int32 count = chain->m_count; - const b2Vec2* vertices = chain->m_vertices; - - b2Vec2 v1 = b2Mul(xf, vertices[0]); - for (int32 i = 1; i < count; ++i) - { - b2Vec2 v2 = b2Mul(xf, vertices[i]); - m_debugDraw->DrawSegment(v1, v2, color); - m_debugDraw->DrawCircle(v1, 0.05f, color); - v1 = v2; - } - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); - int32 vertexCount = poly->m_vertexCount; - b2Assert(vertexCount <= b2_maxPolygonVertices); - b2Vec2 vertices[b2_maxPolygonVertices]; - - for (int32 i = 0; i < vertexCount; ++i) - { - vertices[i] = b2Mul(xf, poly->m_vertices[i]); - } - - m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); - } - break; - - default: - break; - } -} - -void b2World::DrawJoint(b2Joint* joint) -{ - b2Body* bodyA = joint->GetBodyA(); - b2Body* bodyB = joint->GetBodyB(); - const b2Transform& xf1 = bodyA->GetTransform(); - const b2Transform& xf2 = bodyB->GetTransform(); - b2Vec2 x1 = xf1.p; - b2Vec2 x2 = xf2.p; - b2Vec2 p1 = joint->GetAnchorA(); - b2Vec2 p2 = joint->GetAnchorB(); - - b2Color color(0.5f, 0.8f, 0.8f); - - switch (joint->GetType()) - { - case e_distanceJoint: - m_debugDraw->DrawSegment(p1, p2, color); - break; - - case e_pulleyJoint: - { - b2PulleyJoint* pulley = (b2PulleyJoint*)joint; - b2Vec2 s1 = pulley->GetGroundAnchorA(); - b2Vec2 s2 = pulley->GetGroundAnchorB(); - m_debugDraw->DrawSegment(s1, p1, color); - m_debugDraw->DrawSegment(s2, p2, color); - m_debugDraw->DrawSegment(s1, s2, color); - } - break; - - case e_mouseJoint: - // don't draw this - break; - - default: - m_debugDraw->DrawSegment(x1, p1, color); - m_debugDraw->DrawSegment(p1, p2, color); - m_debugDraw->DrawSegment(x2, p2, color); - } -} - -void b2World::DrawDebugData() -{ - if (m_debugDraw == NULL) - { - return; - } - - uint32 flags = m_debugDraw->GetFlags(); - - if (flags & b2Draw::e_shapeBit) - { - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - const b2Transform& xf = b->GetTransform(); - for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) - { - if (b->IsActive() == false) - { - DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); - } - else if (b->GetType() == b2_staticBody) - { - DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); - } - else if (b->GetType() == b2_kinematicBody) - { - DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); - } - else if (b->IsAwake() == false) - { - DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); - } - else - { - DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); - } - } - } - } - - if (flags & b2Draw::e_jointBit) - { - for (b2Joint* j = m_jointList; j; j = j->GetNext()) - { - DrawJoint(j); - } - } - - if (flags & b2Draw::e_pairBit) - { - b2Color color(0.3f, 0.9f, 0.9f); - for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) - { - //b2Fixture* fixtureA = c->GetFixtureA(); - //b2Fixture* fixtureB = c->GetFixtureB(); - - //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); - //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); - - //m_debugDraw->DrawSegment(cA, cB, color); - } - } - - if (flags & b2Draw::e_aabbBit) - { - b2Color color(0.9f, 0.3f, 0.9f); - b2BroadPhase* bp = &m_contactManager.m_broadPhase; - - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - if (b->IsActive() == false) - { - continue; - } - - for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) - { - for (int32 i = 0; i < f->m_proxyCount; ++i) - { - b2FixtureProxy* proxy = f->m_proxies + i; - b2AABB aabb = bp->GetFatAABB(proxy->proxyId); - b2Vec2 vs[4]; - vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); - vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); - vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); - vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); - - m_debugDraw->DrawPolygon(vs, 4, color); - } - } - } - } - - if (flags & b2Draw::e_centerOfMassBit) - { - for (b2Body* b = m_bodyList; b; b = b->GetNext()) - { - b2Transform xf = b->GetTransform(); - xf.p = b->GetWorldCenter(); - m_debugDraw->DrawTransform(xf); - } - } -} - -int32 b2World::GetProxyCount() const -{ - return m_contactManager.m_broadPhase.GetProxyCount(); -} - -int32 b2World::GetTreeHeight() const -{ - return m_contactManager.m_broadPhase.GetTreeHeight(); -} - -int32 b2World::GetTreeBalance() const -{ - return m_contactManager.m_broadPhase.GetTreeBalance(); -} - -float32 b2World::GetTreeQuality() const -{ - return m_contactManager.m_broadPhase.GetTreeQuality(); -} - -void b2World::Dump() -{ - if ((m_flags & e_locked) == e_locked) - { - return; - } - - b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); - b2Log("m_world->SetGravity(g);\n"); - - b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); - b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); - int32 i = 0; - for (b2Body* b = m_bodyList; b; b = b->m_next) - { - b->m_islandIndex = i; - b->Dump(); - ++i; - } - - i = 0; - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - j->m_index = i; - ++i; - } - - // First pass on joints, skip gear joints. - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - if (j->m_type == e_gearJoint) - { - continue; - } - - b2Log("{\n"); - j->Dump(); - b2Log("}\n"); - } - - // Second pass on joints, only gear joints. - for (b2Joint* j = m_jointList; j; j = j->m_next) - { - if (j->m_type != e_gearJoint) - { - continue; - } - - b2Log("{\n"); - j->Dump(); - b2Log("}\n"); - } - - b2Log("b2Free(joints);\n"); - b2Log("b2Free(bodies);\n"); - b2Log("joints = NULL;\n"); - b2Log("bodies = NULL;\n"); -} diff --git a/external/box2d/Dynamics/b2World.h b/external/box2d/Dynamics/b2World.h deleted file mode 100644 index f207930511..0000000000 --- a/external/box2d/Dynamics/b2World.h +++ /dev/null @@ -1,349 +0,0 @@ -/* -* Copyright (c) 2006-2011 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. -*/ - -#ifndef B2_WORLD_H -#define B2_WORLD_H - -#include -#include -#include -#include -#include -#include - -struct b2AABB; -struct b2BodyDef; -struct b2Color; -struct b2JointDef; -class b2Body; -class b2Draw; -class b2Fixture; -class b2Joint; - -/// The world class manages all physics entities, dynamic simulation, -/// and asynchronous queries. The world also contains efficient memory -/// management facilities. -class b2World -{ -public: - /// Construct a world object. - /// @param gravity the world gravity vector. - b2World(const b2Vec2& gravity); - - /// Destruct the world. All physics entities are destroyed and all heap memory is released. - ~b2World(); - - /// Register a destruction listener. The listener is owned by you and must - /// remain in scope. - void SetDestructionListener(b2DestructionListener* listener); - - /// Register a contact filter to provide specific control over collision. - /// Otherwise the default filter is used (b2_defaultFilter). The listener is - /// owned by you and must remain in scope. - void SetContactFilter(b2ContactFilter* filter); - - /// Register a contact event listener. The listener is owned by you and must - /// remain in scope. - void SetContactListener(b2ContactListener* listener); - - /// Register a routine for debug drawing. The debug draw functions are called - /// inside with b2World::DrawDebugData method. The debug draw object is owned - /// by you and must remain in scope. - void SetDebugDraw(b2Draw* debugDraw); - - /// Create a rigid body given a definition. No reference to the definition - /// is retained. - /// @warning This function is locked during callbacks. - b2Body* CreateBody(const b2BodyDef* def); - - /// Destroy a rigid body given a definition. No reference to the definition - /// is retained. This function is locked during callbacks. - /// @warning This automatically deletes all associated shapes and joints. - /// @warning This function is locked during callbacks. - void DestroyBody(b2Body* body); - - /// Create a joint to constrain bodies together. No reference to the definition - /// is retained. This may cause the connected bodies to cease colliding. - /// @warning This function is locked during callbacks. - b2Joint* CreateJoint(const b2JointDef* def); - - /// Destroy a joint. This may cause the connected bodies to begin colliding. - /// @warning This function is locked during callbacks. - void DestroyJoint(b2Joint* joint); - - /// Take a time step. This performs collision detection, integration, - /// and constraint solution. - /// @param timeStep the amount of time to simulate, this should not vary. - /// @param velocityIterations for the velocity constraint solver. - /// @param positionIterations for the position constraint solver. - void Step( float32 timeStep, - int32 velocityIterations, - int32 positionIterations); - - /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically - /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. - /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain - /// a fixed sized time step under a variable frame-rate. - /// When you perform sub-stepping you will disable auto clearing of forces and instead call - /// ClearForces after all sub-steps are complete in one pass of your game loop. - /// @see SetAutoClearForces - void ClearForces(); - - /// Call this to draw shapes and other debug draw data. - void DrawDebugData(); - - /// Query the world for all fixtures that potentially overlap the - /// provided AABB. - /// @param callback a user implemented callback class. - /// @param aabb the query box. - void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; - - /// Ray-cast the world for all fixtures in the path of the ray. Your callback - /// controls whether you get the closest point, any point, or n-points. - /// The ray-cast ignores shapes that contain the starting point. - /// @param callback a user implemented callback class. - /// @param point1 the ray starting point - /// @param point2 the ray ending point - void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; - - /// Get the world body list. With the returned body, use b2Body::GetNext to get - /// the next body in the world list. A NULL body indicates the end of the list. - /// @return the head of the world body list. - b2Body* GetBodyList(); - const b2Body* GetBodyList() const; - - /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get - /// the next joint in the world list. A NULL joint indicates the end of the list. - /// @return the head of the world joint list. - b2Joint* GetJointList(); - const b2Joint* GetJointList() const; - - /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get - /// the next contact in the world list. A NULL contact indicates the end of the list. - /// @return the head of the world contact list. - /// @warning contacts are created and destroyed in the middle of a time step. - /// Use b2ContactListener to avoid missing contacts. - b2Contact* GetContactList(); - const b2Contact* GetContactList() const; - - /// Enable/disable sleep. - void SetAllowSleeping(bool flag); - bool GetAllowSleeping() const { return m_allowSleep; } - - /// Enable/disable warm starting. For testing. - void SetWarmStarting(bool flag) { m_warmStarting = flag; } - bool GetWarmStarting() const { return m_warmStarting; } - - /// Enable/disable continuous physics. For testing. - void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } - bool GetContinuousPhysics() const { return m_continuousPhysics; } - - /// Enable/disable single stepped continuous physics. For testing. - void SetSubStepping(bool flag) { m_subStepping = flag; } - bool GetSubStepping() const { return m_subStepping; } - - /// Get the number of broad-phase proxies. - int32 GetProxyCount() const; - - /// Get the number of bodies. - int32 GetBodyCount() const; - - /// Get the number of joints. - int32 GetJointCount() const; - - /// Get the number of contacts (each may have 0 or more contact points). - int32 GetContactCount() const; - - /// Get the height of the dynamic tree. - int32 GetTreeHeight() const; - - /// Get the balance of the dynamic tree. - int32 GetTreeBalance() const; - - /// Get the quality metric of the dynamic tree. The smaller the better. - /// The minimum is 1. - float32 GetTreeQuality() const; - - /// Change the global gravity vector. - void SetGravity(const b2Vec2& gravity); - - /// Get the global gravity vector. - b2Vec2 GetGravity() const; - - /// Is the world locked (in the middle of a time step). - bool IsLocked() const; - - /// Set flag to control automatic clearing of forces after each time step. - void SetAutoClearForces(bool flag); - - /// Get the flag that controls automatic clearing of forces after each time step. - bool GetAutoClearForces() const; - - /// Get the contact manager for testing. - const b2ContactManager& GetContactManager() const; - - /// Get the current profile. - const b2Profile& GetProfile() const; - - /// Dump the world into the log file. - /// @warning this should be called outside of a time step. - void Dump(); - -private: - - // m_flags - enum - { - e_newFixture = 0x0001, - e_locked = 0x0002, - e_clearForces = 0x0004 - }; - - friend class b2Body; - friend class b2Fixture; - friend class b2ContactManager; - friend class b2Controller; - - void Solve(const b2TimeStep& step); - void SolveTOI(const b2TimeStep& step); - - void DrawJoint(b2Joint* joint); - void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); - - b2BlockAllocator m_blockAllocator; - b2StackAllocator m_stackAllocator; - - int32 m_flags; - - b2ContactManager m_contactManager; - - b2Body* m_bodyList; - b2Joint* m_jointList; - - int32 m_bodyCount; - int32 m_jointCount; - - b2Vec2 m_gravity; - bool m_allowSleep; - - b2DestructionListener* m_destructionListener; - b2Draw* m_debugDraw; - - // This is used to compute the time step ratio to - // support a variable time step. - float32 m_inv_dt0; - - // These are for debugging the solver. - bool m_warmStarting; - bool m_continuousPhysics; - bool m_subStepping; - - bool m_stepComplete; - - b2Profile m_profile; -}; - -inline b2Body* b2World::GetBodyList() -{ - return m_bodyList; -} - -inline const b2Body* b2World::GetBodyList() const -{ - return m_bodyList; -} - -inline b2Joint* b2World::GetJointList() -{ - return m_jointList; -} - -inline const b2Joint* b2World::GetJointList() const -{ - return m_jointList; -} - -inline b2Contact* b2World::GetContactList() -{ - return m_contactManager.m_contactList; -} - -inline const b2Contact* b2World::GetContactList() const -{ - return m_contactManager.m_contactList; -} - -inline int32 b2World::GetBodyCount() const -{ - return m_bodyCount; -} - -inline int32 b2World::GetJointCount() const -{ - return m_jointCount; -} - -inline int32 b2World::GetContactCount() const -{ - return m_contactManager.m_contactCount; -} - -inline void b2World::SetGravity(const b2Vec2& gravity) -{ - m_gravity = gravity; -} - -inline b2Vec2 b2World::GetGravity() const -{ - return m_gravity; -} - -inline bool b2World::IsLocked() const -{ - return (m_flags & e_locked) == e_locked; -} - -inline void b2World::SetAutoClearForces(bool flag) -{ - if (flag) - { - m_flags |= e_clearForces; - } - else - { - m_flags &= ~e_clearForces; - } -} - -/// Get the flag that controls automatic clearing of forces after each time step. -inline bool b2World::GetAutoClearForces() const -{ - return (m_flags & e_clearForces) == e_clearForces; -} - -inline const b2ContactManager& b2World::GetContactManager() const -{ - return m_contactManager; -} - -inline const b2Profile& b2World::GetProfile() const -{ - return m_profile; -} - -#endif diff --git a/external/box2d/Dynamics/b2WorldCallbacks.cpp b/external/box2d/Dynamics/b2WorldCallbacks.cpp deleted file mode 100644 index 48ad0cc46a..0000000000 --- a/external/box2d/Dynamics/b2WorldCallbacks.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright (c) 2006-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 -#include - -// Return true if contact calculations should be performed between these two shapes. -// If you implement your own collision filter you may want to build from this implementation. -bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) -{ - const b2Filter& filterA = fixtureA->GetFilterData(); - const b2Filter& filterB = fixtureB->GetFilterData(); - - if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) - { - return filterA.groupIndex > 0; - } - - bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; - return collide; -} diff --git a/external/box2d/Dynamics/b2WorldCallbacks.h b/external/box2d/Dynamics/b2WorldCallbacks.h deleted file mode 100644 index 86c04e3e32..0000000000 --- a/external/box2d/Dynamics/b2WorldCallbacks.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -* Copyright (c) 2006-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. -*/ - -#ifndef B2_WORLD_CALLBACKS_H -#define B2_WORLD_CALLBACKS_H - -#include - -struct b2Vec2; -struct b2Transform; -class b2Fixture; -class b2Body; -class b2Joint; -class b2Contact; -struct b2ContactResult; -struct b2Manifold; - -/// Joints and fixtures are destroyed when their associated -/// body is destroyed. Implement this listener so that you -/// may nullify references to these joints and shapes. -class b2DestructionListener -{ -public: - virtual ~b2DestructionListener() {} - - /// Called when any joint is about to be destroyed due - /// to the destruction of one of its attached bodies. - virtual void SayGoodbye(b2Joint* joint) = 0; - - /// Called when any fixture is about to be destroyed due - /// to the destruction of its parent body. - virtual void SayGoodbye(b2Fixture* fixture) = 0; -}; - -/// Implement this class to provide collision filtering. In other words, you can implement -/// this class if you want finer control over contact creation. -class b2ContactFilter -{ -public: - virtual ~b2ContactFilter() {} - - /// Return true if contact calculations should be performed between these two shapes. - /// @warning for performance reasons this is only called when the AABBs begin to overlap. - virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); -}; - -/// Contact impulses for reporting. Impulses are used instead of forces because -/// sub-step forces may approach infinity for rigid body collisions. These -/// match up one-to-one with the contact points in b2Manifold. -struct b2ContactImpulse -{ - float32 normalImpulses[b2_maxManifoldPoints]; - float32 tangentImpulses[b2_maxManifoldPoints]; - int32 count; -}; - -/// Implement this class to get contact information. You can use these results for -/// things like sounds and game logic. You can also get contact results by -/// traversing the contact lists after the time step. However, you might miss -/// some contacts because continuous physics leads to sub-stepping. -/// Additionally you may receive multiple callbacks for the same contact in a -/// single time step. -/// You should strive to make your callbacks efficient because there may be -/// many callbacks per time step. -/// @warning You cannot create/destroy Box2D entities inside these callbacks. -class b2ContactListener -{ -public: - virtual ~b2ContactListener() {} - - /// Called when two fixtures begin to touch. - virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } - - /// Called when two fixtures cease to touch. - virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } - - /// This is called after a contact is updated. This allows you to inspect a - /// contact before it goes to the solver. If you are careful, you can modify the - /// contact manifold (e.g. disable contact). - /// A copy of the old manifold is provided so that you can detect changes. - /// Note: this is called only for awake bodies. - /// Note: this is called even when the number of contact points is zero. - /// Note: this is not called for sensors. - /// Note: if you set the number of contact points to zero, you will not - /// get an EndContact callback. However, you may get a BeginContact callback - /// the next step. - virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) - { - B2_NOT_USED(contact); - B2_NOT_USED(oldManifold); - } - - /// This lets you inspect a contact after the solver is finished. This is useful - /// for inspecting impulses. - /// Note: the contact manifold does not include time of impact impulses, which can be - /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly - /// in a separate data structure. - /// Note: this is only called for contacts that are touching, solid, and awake. - virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) - { - B2_NOT_USED(contact); - B2_NOT_USED(impulse); - } -}; - -/// Callback class for AABB queries. -/// See b2World::Query -class b2QueryCallback -{ -public: - virtual ~b2QueryCallback() {} - - /// Called for each fixture found in the query AABB. - /// @return false to terminate the query. - virtual bool ReportFixture(b2Fixture* fixture) = 0; -}; - -/// Callback class for ray casts. -/// See b2World::RayCast -class b2RayCastCallback -{ -public: - virtual ~b2RayCastCallback() {} - - /// Called for each fixture found in the query. You control how the ray cast - /// proceeds by returning a float: - /// return -1: ignore this fixture and continue - /// return 0: terminate the ray cast - /// return fraction: clip the ray to this point - /// return 1: don't clip the ray and continue - /// @param fixture the fixture hit by the ray - /// @param point the point of initial intersection - /// @param normal the normal vector at the point of intersection - /// @return -1 to filter, 0 to terminate, fraction to clip the ray for - /// closest hit, 1 to continue - virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, - const b2Vec2& normal, float32 fraction) = 0; -}; - -#endif diff --git a/external/box2d/Rope/b2Rope.cpp b/external/box2d/Rope/b2Rope.cpp deleted file mode 100644 index 9bf671aec9..0000000000 --- a/external/box2d/Rope/b2Rope.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* -* Copyright (c) 2011 Erin Catto http://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 -#include - -b2Rope::b2Rope() -{ - m_count = 0; - m_ps = NULL; - m_p0s = NULL; - m_vs = NULL; - m_ims = NULL; - m_Ls = NULL; - m_as = NULL; - m_gravity.SetZero(); - m_k2 = 1.0f; - m_k3 = 0.1f; -} - -b2Rope::~b2Rope() -{ - b2Free(m_ps); - b2Free(m_p0s); - b2Free(m_vs); - b2Free(m_ims); - b2Free(m_Ls); - b2Free(m_as); -} - -void b2Rope::Initialize(const b2RopeDef* def) -{ - b2Assert(def->count >= 3); - m_count = def->count; - m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); - m_ims = (float32*)b2Alloc(m_count * sizeof(float32)); - - for (int32 i = 0; i < m_count; ++i) - { - m_ps[i] = def->vertices[i]; - m_p0s[i] = def->vertices[i]; - m_vs[i].SetZero(); - - float32 m = def->masses[i]; - if (m > 0.0f) - { - m_ims[i] = 1.0f / m; - } - else - { - m_ims[i] = 0.0f; - } - } - - int32 count2 = m_count - 1; - int32 count3 = m_count - 2; - m_Ls = (float32*)b2Alloc(count2 * sizeof(float32)); - m_as = (float32*)b2Alloc(count3 * sizeof(float32)); - - for (int32 i = 0; i < count2; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i+1]; - m_Ls[i] = b2Distance(p1, p2); - } - - for (int32 i = 0; i < count3; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - b2Vec2 p3 = m_ps[i + 2]; - - b2Vec2 d1 = p2 - p1; - b2Vec2 d2 = p3 - p2; - - float32 a = b2Cross(d1, d2); - float32 b = b2Dot(d1, d2); - - m_as[i] = b2Atan2(a, b); - } - - m_gravity = def->gravity; - m_damping = def->damping; - m_k2 = def->k2; - m_k3 = def->k3; -} - -void b2Rope::Step(float32 h, int32 iterations) -{ - if (h == 0.0) - { - return; - } - - float32 d = expf(- h * m_damping); - - for (int32 i = 0; i < m_count; ++i) - { - m_p0s[i] = m_ps[i]; - if (m_ims[i] > 0.0f) - { - m_vs[i] += h * m_gravity; - } - m_vs[i] *= d; - m_ps[i] += h * m_vs[i]; - - } - - for (int32 i = 0; i < iterations; ++i) - { - SolveC2(); - SolveC3(); - SolveC2(); - } - - float32 inv_h = 1.0f / h; - for (int32 i = 0; i < m_count; ++i) - { - m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]); - } -} - -void b2Rope::SolveC2() -{ - int32 count2 = m_count - 1; - - for (int32 i = 0; i < count2; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - - b2Vec2 d = p2 - p1; - float32 L = d.Normalize(); - - float32 im1 = m_ims[i]; - float32 im2 = m_ims[i + 1]; - - if (im1 + im2 == 0.0f) - { - continue; - } - - float32 s1 = im1 / (im1 + im2); - float32 s2 = im2 / (im1 + im2); - - p1 -= m_k2 * s1 * (m_Ls[i] - L) * d; - p2 += m_k2 * s2 * (m_Ls[i] - L) * d; - - m_ps[i] = p1; - m_ps[i + 1] = p2; - } -} - -void b2Rope::SetAngle(float32 angle) -{ - int32 count3 = m_count - 2; - for (int32 i = 0; i < count3; ++i) - { - m_as[i] = angle; - } -} - -void b2Rope::SolveC3() -{ - int32 count3 = m_count - 2; - - for (int32 i = 0; i < count3; ++i) - { - b2Vec2 p1 = m_ps[i]; - b2Vec2 p2 = m_ps[i + 1]; - b2Vec2 p3 = m_ps[i + 2]; - - float32 m1 = m_ims[i]; - float32 m2 = m_ims[i + 1]; - float32 m3 = m_ims[i + 2]; - - b2Vec2 d1 = p2 - p1; - b2Vec2 d2 = p3 - p2; - - float32 L1sqr = d1.LengthSquared(); - float32 L2sqr = d2.LengthSquared(); - - if (L1sqr * L2sqr == 0.0f) - { - continue; - } - - float32 a = b2Cross(d1, d2); - float32 b = b2Dot(d1, d2); - - float32 angle = b2Atan2(a, b); - - b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew(); - b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew(); - - b2Vec2 J1 = -Jd1; - b2Vec2 J2 = Jd1 - Jd2; - b2Vec2 J3 = Jd2; - - float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3); - if (mass == 0.0f) - { - continue; - } - - mass = 1.0f / mass; - - float32 C = angle - m_as[i]; - - while (C > b2_pi) - { - angle -= 2 * b2_pi; - C = angle - m_as[i]; - } - - while (C < -b2_pi) - { - angle += 2.0f * b2_pi; - C = angle - m_as[i]; - } - - float32 impulse = - m_k3 * mass * C; - - p1 += (m1 * impulse) * J1; - p2 += (m2 * impulse) * J2; - p3 += (m3 * impulse) * J3; - - m_ps[i] = p1; - m_ps[i + 1] = p2; - m_ps[i + 2] = p3; - } -} - -void b2Rope::Draw(b2Draw* draw) const -{ - b2Color c(0.4f, 0.5f, 0.7f); - - for (int32 i = 0; i < m_count - 1; ++i) - { - draw->DrawSegment(m_ps[i], m_ps[i+1], c); - } -} diff --git a/external/box2d/Rope/b2Rope.h b/external/box2d/Rope/b2Rope.h deleted file mode 100644 index b981dfd6c5..0000000000 --- a/external/box2d/Rope/b2Rope.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef B2_ROPE_H -#define B2_ROPE_H - -#include - -class b2Draw; - -/// -struct b2RopeDef -{ - b2RopeDef() - { - vertices = NULL; - count = 0; - masses = NULL; - gravity.SetZero(); - damping = 0.1f; - k2 = 0.9f; - k3 = 0.1f; - } - - /// - b2Vec2* vertices; - - /// - int32 count; - - /// - float32* masses; - - /// - b2Vec2 gravity; - - /// - float32 damping; - - /// Stretching stiffness - float32 k2; - - /// Bending stiffness. Values above 0.5 can make the simulation blow up. - float32 k3; -}; - -/// -class b2Rope -{ -public: - b2Rope(); - ~b2Rope(); - - /// - void Initialize(const b2RopeDef* def); - - /// - void Step(float32 timeStep, int32 iterations); - - /// - int32 GetVertexCount() const - { - return m_count; - } - - /// - const b2Vec2* GetVertices() const - { - return m_ps; - } - - /// - void Draw(b2Draw* draw) const; - - /// - void SetAngle(float32 angle); - -private: - - void SolveC2(); - void SolveC3(); - - int32 m_count; - b2Vec2* m_ps; - b2Vec2* m_p0s; - b2Vec2* m_vs; - - float32* m_ims; - - float32* m_Ls; - float32* m_as; - - b2Vec2 m_gravity; - float32 m_damping; - - float32 m_k2; - float32 m_k3; -}; - -#endif diff --git a/external/box2d/proj.linux/.cproject b/external/box2d/proj.linux/.cproject deleted file mode 100644 index 5aa092cac3..0000000000 --- a/external/box2d/proj.linux/.cproject +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/box2d/proj.linux/.project b/external/box2d/proj.linux/.project deleted file mode 100644 index 164d50f52a..0000000000 --- a/external/box2d/proj.linux/.project +++ /dev/null @@ -1,110 +0,0 @@ - - - libBox2D - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/libBox2D/Debug} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - - - Box2D.h - 1 - PARENT-1-PROJECT_LOC/Box2D.h - - - Collision - 2 - PARENT-1-PROJECT_LOC/Collision - - - Common - 2 - PARENT-1-PROJECT_LOC/Common - - - Dynamics - 2 - PARENT-1-PROJECT_LOC/Dynamics - - - Rope - 2 - PARENT-1-PROJECT_LOC/Rope - - - diff --git a/external/box2d/proj.linux/Makefile b/external/box2d/proj.linux/Makefile deleted file mode 100644 index e430bc9883..0000000000 --- a/external/box2d/proj.linux/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -TARGET = libbox2d.a - -SOURCES = ../Collision/Shapes/b2ChainShape.cpp \ -../Collision/Shapes/b2CircleShape.cpp \ -../Collision/Shapes/b2EdgeShape.cpp \ -../Collision/Shapes/b2PolygonShape.cpp \ -../Collision/b2BroadPhase.cpp \ -../Collision/b2CollideCircle.cpp \ -../Collision/b2CollideEdge.cpp \ -../Collision/b2CollidePolygon.cpp \ -../Collision/b2Collision.cpp \ -../Collision/b2Distance.cpp \ -../Collision/b2DynamicTree.cpp \ -../Collision/b2TimeOfImpact.cpp \ -../Common/b2BlockAllocator.cpp \ -../Common/b2Draw.cpp \ -../Common/b2Math.cpp \ -../Common/b2Settings.cpp \ -../Common/b2StackAllocator.cpp \ -../Common/b2Timer.cpp \ -../Dynamics/Contacts/b2ChainAndCircleContact.cpp \ -../Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ -../Dynamics/Contacts/b2CircleContact.cpp \ -../Dynamics/Contacts/b2Contact.cpp \ -../Dynamics/Contacts/b2ContactSolver.cpp \ -../Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ -../Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ -../Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ -../Dynamics/Contacts/b2PolygonContact.cpp \ -../Dynamics/Joints/b2DistanceJoint.cpp \ -../Dynamics/Joints/b2FrictionJoint.cpp \ -../Dynamics/Joints/b2GearJoint.cpp \ -../Dynamics/Joints/b2Joint.cpp \ -../Dynamics/Joints/b2MouseJoint.cpp \ -../Dynamics/Joints/b2PrismaticJoint.cpp \ -../Dynamics/Joints/b2PulleyJoint.cpp \ -../Dynamics/Joints/b2RevoluteJoint.cpp \ -../Dynamics/Joints/b2RopeJoint.cpp \ -../Dynamics/Joints/b2WeldJoint.cpp \ -../Dynamics/Joints/b2WheelJoint.cpp \ -../Dynamics/b2Body.cpp \ -../Dynamics/b2ContactManager.cpp \ -../Dynamics/b2Fixture.cpp \ -../Dynamics/b2Island.cpp \ -../Dynamics/b2World.cpp \ -../Dynamics/b2WorldCallbacks.cpp \ -../Rope/b2Rope.cpp - -include ../../../cocos2dx/proj.linux/cocos2dx.mk - -INCLUDES = -I../.. - -# Cocos2d is not responsible for warnings in external projects -CXXFLAGS += -w - -ifeq ($(DEBUG), 1) -DEFINES = -D_DEBUG -else -DEFINES = -endif - -TARGET := $(LIB_DIR)/$(TARGET) - -all: $(TARGET) - -$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_AR)$(AR) $(ARFLAGS) $(TARGET) $(OBJECTS) - -$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) - @mkdir -p $(@D) - $(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/external/box2d/proj.linux/box2d.prf b/external/box2d/proj.linux/box2d.prf deleted file mode 100644 index 434ad88406..0000000000 --- a/external/box2d/proj.linux/box2d.prf +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Do not include this file in your project: see cocos2dx.pri. -################################################################################ - -linux { - # We will compile box2d on demand using Makefile. - build_box2d.name = Build box2d static library - build_box2d.input = $$PWD/Makefile - build_box2d.output = $$CC_LIBRARY_DIR/libbox2d.a - build_box2d.target = $$CC_LIBRARY_DIR/libbox2d.a - build_box2d.CONFIG = no_link target_predeps - build_box2d.commands = cd $$PWD && make $$CC_MAKE_FLAGS - - QMAKE_EXTRA_COMPILERS += build_box2d - QMAKE_EXTRA_TARGETS += build_box2d - - PRE_TARGETDEPS += $$CC_LIBRARY_DIR/libbox2d.a - LIBS += -Wl,-Bstatic -lbox2d -Wl,-Bdynamic -} diff --git a/external/box2d/proj.win32/Box2D.vcxproj b/external/box2d/proj.win32/Box2D.vcxproj deleted file mode 100644 index cd4bd2086c..0000000000 --- a/external/box2d/proj.win32/Box2D.vcxproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - libBox2D - {929480E7-23C0-4DF6-8456-096D71547116} - Box2D.win32 - Win32Proj - - - - StaticLibrary - Unicode - v100 - v110 - v110_xp - - - StaticLibrary - Unicode - v100 - v110 - v110_xp - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration).win32\ - $(Configuration).win32\ - $(SolutionDir)$(Configuration).win32\ - $(Configuration).win32\ - AllRules.ruleset - - - AllRules.ruleset - - - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) - - - - Disabled - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - true - - - $(OutDir)$(ProjectName).lib - - - - - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - - - $(OutDir)$(ProjectName).lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/external/box2d/proj.win32/Box2D.vcxproj.filters b/external/box2d/proj.win32/Box2D.vcxproj.filters deleted file mode 100644 index e810cbb0cf..0000000000 --- a/external/box2d/proj.win32/Box2D.vcxproj.filters +++ /dev/null @@ -1,301 +0,0 @@ - - - - - {bdf099c5-cc32-468b-b53f-ec010d7f823f} - - - {92792f88-4e5c-46ee-8d87-002f3b2297ae} - - - {f41a6fa6-5ac1-4514-9ac0-6f3a38f35b4d} - - - {0b56913a-34b7-410a-b386-869d6f7a20be} - - - {f0e7b230-79cc-49b8-9ed7-9dbfa062f2a4} - - - {932f2008-afbe-42f5-993d-a1df0ec67756} - - - {f8937e09-93a4-49fa-8f3e-dfc36da764df} - - - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Rope - - - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Collision\Shapes - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Contacts - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Dynamics\Joints - - - Rope - - - - \ No newline at end of file diff --git a/external/box2d/proj.win32/Box2D.vcxproj.user b/external/box2d/proj.win32/Box2D.vcxproj.user deleted file mode 100644 index ace9a86acb..0000000000 --- a/external/box2d/proj.win32/Box2D.vcxproj.user +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file From a96fc9dc16a84baca679449ab70b2ccb80c94742 Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 14:15:32 +0800 Subject: [PATCH 112/116] issue #2905:add Box2D --- external/Box2D/Android.mk | 60 + external/Box2D/Box2D.h | 67 + .../Box2D/Collision/Shapes/b2ChainShape.cpp | 171 +++ .../Box2D/Collision/Shapes/b2ChainShape.h | 102 ++ .../Box2D/Collision/Shapes/b2CircleShape.cpp | 100 ++ .../Box2D/Collision/Shapes/b2CircleShape.h | 91 ++ .../Box2D/Collision/Shapes/b2EdgeShape.cpp | 139 ++ external/Box2D/Collision/Shapes/b2EdgeShape.h | 74 + .../Box2D/Collision/Shapes/b2PolygonShape.cpp | 361 +++++ .../Box2D/Collision/Shapes/b2PolygonShape.h | 95 ++ external/Box2D/Collision/Shapes/b2Shape.h | 101 ++ external/Box2D/Collision/b2BroadPhase.cpp | 122 ++ external/Box2D/Collision/b2BroadPhase.h | 248 ++++ external/Box2D/Collision/b2CollideCircle.cpp | 154 ++ external/Box2D/Collision/b2CollideEdge.cpp | 698 +++++++++ external/Box2D/Collision/b2CollidePolygon.cpp | 317 ++++ external/Box2D/Collision/b2Collision.cpp | 249 ++++ external/Box2D/Collision/b2Collision.h | 276 ++++ external/Box2D/Collision/b2Distance.cpp | 603 ++++++++ external/Box2D/Collision/b2Distance.h | 141 ++ external/Box2D/Collision/b2DynamicTree.cpp | 775 ++++++++++ external/Box2D/Collision/b2DynamicTree.h | 284 ++++ external/Box2D/Collision/b2TimeOfImpact.cpp | 488 ++++++ external/Box2D/Collision/b2TimeOfImpact.h | 58 + external/Box2D/Common/b2BlockAllocator.cpp | 218 +++ external/Box2D/Common/b2BlockAllocator.h | 62 + external/Box2D/Common/b2Draw.cpp | 44 + external/Box2D/Common/b2Draw.h | 81 + external/Box2D/Common/b2GrowableStack.h | 85 ++ external/Box2D/Common/b2Math.cpp | 94 ++ external/Box2D/Common/b2Math.h | 738 +++++++++ external/Box2D/Common/b2Settings.cpp | 61 + external/Box2D/Common/b2Settings.h | 150 ++ external/Box2D/Common/b2StackAllocator.cpp | 83 ++ external/Box2D/Common/b2StackAllocator.h | 60 + external/Box2D/Common/b2Timer.cpp | 100 ++ external/Box2D/Common/b2Timer.h | 45 + .../Contacts/b2ChainAndCircleContact.cpp | 54 + .../Contacts/b2ChainAndCircleContact.h | 39 + .../Contacts/b2ChainAndPolygonContact.cpp | 54 + .../Contacts/b2ChainAndPolygonContact.h | 39 + .../Dynamics/Contacts/b2CircleContact.cpp | 53 + .../Box2D/Dynamics/Contacts/b2CircleContact.h | 39 + .../Box2D/Dynamics/Contacts/b2Contact.cpp | 240 +++ external/Box2D/Dynamics/Contacts/b2Contact.h | 331 +++++ .../Dynamics/Contacts/b2ContactSolver.cpp | 832 +++++++++++ .../Box2D/Dynamics/Contacts/b2ContactSolver.h | 94 ++ .../Contacts/b2EdgeAndCircleContact.cpp | 50 + .../Contacts/b2EdgeAndCircleContact.h | 39 + .../Contacts/b2EdgeAndPolygonContact.cpp | 50 + .../Contacts/b2EdgeAndPolygonContact.h | 39 + .../Contacts/b2PolygonAndCircleContact.cpp | 50 + .../Contacts/b2PolygonAndCircleContact.h | 38 + .../Dynamics/Contacts/b2PolygonContact.cpp | 53 + .../Dynamics/Contacts/b2PolygonContact.h | 39 + .../Box2D/Dynamics/Joints/b2DistanceJoint.cpp | 260 ++++ .../Box2D/Dynamics/Joints/b2DistanceJoint.h | 169 +++ .../Box2D/Dynamics/Joints/b2FrictionJoint.cpp | 251 ++++ .../Box2D/Dynamics/Joints/b2FrictionJoint.h | 119 ++ .../Box2D/Dynamics/Joints/b2GearJoint.cpp | 423 ++++++ external/Box2D/Dynamics/Joints/b2GearJoint.h | 125 ++ external/Box2D/Dynamics/Joints/b2Joint.cpp | 199 +++ external/Box2D/Dynamics/Joints/b2Joint.h | 222 +++ .../Box2D/Dynamics/Joints/b2MouseJoint.cpp | 217 +++ external/Box2D/Dynamics/Joints/b2MouseJoint.h | 126 ++ .../Dynamics/Joints/b2PrismaticJoint.cpp | 637 ++++++++ .../Box2D/Dynamics/Joints/b2PrismaticJoint.h | 196 +++ .../Box2D/Dynamics/Joints/b2PulleyJoint.cpp | 332 +++++ .../Box2D/Dynamics/Joints/b2PulleyJoint.h | 143 ++ .../Box2D/Dynamics/Joints/b2RevoluteJoint.cpp | 504 +++++++ .../Box2D/Dynamics/Joints/b2RevoluteJoint.h | 204 +++ .../Box2D/Dynamics/Joints/b2RopeJoint.cpp | 241 +++ external/Box2D/Dynamics/Joints/b2RopeJoint.h | 114 ++ .../Box2D/Dynamics/Joints/b2WeldJoint.cpp | 330 +++++ external/Box2D/Dynamics/Joints/b2WeldJoint.h | 126 ++ .../Box2D/Dynamics/Joints/b2WheelJoint.cpp | 419 ++++++ external/Box2D/Dynamics/Joints/b2WheelJoint.h | 213 +++ external/Box2D/Dynamics/b2Body.cpp | 514 +++++++ external/Box2D/Dynamics/b2Body.h | 846 +++++++++++ external/Box2D/Dynamics/b2ContactManager.cpp | 293 ++++ external/Box2D/Dynamics/b2ContactManager.h | 52 + external/Box2D/Dynamics/b2Fixture.cpp | 303 ++++ external/Box2D/Dynamics/b2Fixture.h | 345 +++++ external/Box2D/Dynamics/b2Island.cpp | 539 +++++++ external/Box2D/Dynamics/b2Island.h | 93 ++ external/Box2D/Dynamics/b2TimeStep.h | 70 + external/Box2D/Dynamics/b2World.cpp | 1316 +++++++++++++++++ external/Box2D/Dynamics/b2World.h | 349 +++++ external/Box2D/Dynamics/b2WorldCallbacks.cpp | 36 + external/Box2D/Dynamics/b2WorldCallbacks.h | 155 ++ external/Box2D/Rope/b2Rope.cpp | 259 ++++ external/Box2D/Rope/b2Rope.h | 115 ++ external/Box2D/proj.linux/.cproject | 267 ++++ external/Box2D/proj.linux/.project | 110 ++ external/Box2D/proj.linux/Makefile | 72 + external/Box2D/proj.linux/box2d.prf | 19 + external/Box2D/proj.win32/Box2D.vcxproj | 194 +++ .../Box2D/proj.win32/Box2D.vcxproj.filters | 301 ++++ external/Box2D/proj.win32/Box2D.vcxproj.user | 3 + 99 files changed, 21549 insertions(+) create mode 100644 external/Box2D/Android.mk create mode 100644 external/Box2D/Box2D.h create mode 100644 external/Box2D/Collision/Shapes/b2ChainShape.cpp create mode 100644 external/Box2D/Collision/Shapes/b2ChainShape.h create mode 100644 external/Box2D/Collision/Shapes/b2CircleShape.cpp create mode 100644 external/Box2D/Collision/Shapes/b2CircleShape.h create mode 100644 external/Box2D/Collision/Shapes/b2EdgeShape.cpp create mode 100644 external/Box2D/Collision/Shapes/b2EdgeShape.h create mode 100644 external/Box2D/Collision/Shapes/b2PolygonShape.cpp create mode 100644 external/Box2D/Collision/Shapes/b2PolygonShape.h create mode 100644 external/Box2D/Collision/Shapes/b2Shape.h create mode 100644 external/Box2D/Collision/b2BroadPhase.cpp create mode 100644 external/Box2D/Collision/b2BroadPhase.h create mode 100644 external/Box2D/Collision/b2CollideCircle.cpp create mode 100644 external/Box2D/Collision/b2CollideEdge.cpp create mode 100644 external/Box2D/Collision/b2CollidePolygon.cpp create mode 100644 external/Box2D/Collision/b2Collision.cpp create mode 100644 external/Box2D/Collision/b2Collision.h create mode 100644 external/Box2D/Collision/b2Distance.cpp create mode 100644 external/Box2D/Collision/b2Distance.h create mode 100644 external/Box2D/Collision/b2DynamicTree.cpp create mode 100644 external/Box2D/Collision/b2DynamicTree.h create mode 100644 external/Box2D/Collision/b2TimeOfImpact.cpp create mode 100644 external/Box2D/Collision/b2TimeOfImpact.h create mode 100644 external/Box2D/Common/b2BlockAllocator.cpp create mode 100644 external/Box2D/Common/b2BlockAllocator.h create mode 100644 external/Box2D/Common/b2Draw.cpp create mode 100644 external/Box2D/Common/b2Draw.h create mode 100644 external/Box2D/Common/b2GrowableStack.h create mode 100644 external/Box2D/Common/b2Math.cpp create mode 100644 external/Box2D/Common/b2Math.h create mode 100644 external/Box2D/Common/b2Settings.cpp create mode 100644 external/Box2D/Common/b2Settings.h create mode 100644 external/Box2D/Common/b2StackAllocator.cpp create mode 100644 external/Box2D/Common/b2StackAllocator.h create mode 100644 external/Box2D/Common/b2Timer.cpp create mode 100644 external/Box2D/Common/b2Timer.h create mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2CircleContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2CircleContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2Contact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2Contact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2ContactSolver.h create mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h create mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp create mode 100644 external/Box2D/Dynamics/Contacts/b2PolygonContact.h create mode 100644 external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2DistanceJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2FrictionJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2GearJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2GearJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2Joint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2Joint.h create mode 100644 external/Box2D/Dynamics/Joints/b2MouseJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2MouseJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2PrismaticJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2PulleyJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2RevoluteJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2RopeJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2RopeJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2WeldJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2WeldJoint.h create mode 100644 external/Box2D/Dynamics/Joints/b2WheelJoint.cpp create mode 100644 external/Box2D/Dynamics/Joints/b2WheelJoint.h create mode 100644 external/Box2D/Dynamics/b2Body.cpp create mode 100644 external/Box2D/Dynamics/b2Body.h create mode 100644 external/Box2D/Dynamics/b2ContactManager.cpp create mode 100644 external/Box2D/Dynamics/b2ContactManager.h create mode 100644 external/Box2D/Dynamics/b2Fixture.cpp create mode 100644 external/Box2D/Dynamics/b2Fixture.h create mode 100644 external/Box2D/Dynamics/b2Island.cpp create mode 100644 external/Box2D/Dynamics/b2Island.h create mode 100644 external/Box2D/Dynamics/b2TimeStep.h create mode 100644 external/Box2D/Dynamics/b2World.cpp create mode 100644 external/Box2D/Dynamics/b2World.h create mode 100644 external/Box2D/Dynamics/b2WorldCallbacks.cpp create mode 100644 external/Box2D/Dynamics/b2WorldCallbacks.h create mode 100644 external/Box2D/Rope/b2Rope.cpp create mode 100644 external/Box2D/Rope/b2Rope.h create mode 100644 external/Box2D/proj.linux/.cproject create mode 100644 external/Box2D/proj.linux/.project create mode 100644 external/Box2D/proj.linux/Makefile create mode 100644 external/Box2D/proj.linux/box2d.prf create mode 100644 external/Box2D/proj.win32/Box2D.vcxproj create mode 100644 external/Box2D/proj.win32/Box2D.vcxproj.filters create mode 100644 external/Box2D/proj.win32/Box2D.vcxproj.user diff --git a/external/Box2D/Android.mk b/external/Box2D/Android.mk new file mode 100644 index 0000000000..c366750c01 --- /dev/null +++ b/external/Box2D/Android.mk @@ -0,0 +1,60 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := box2d_static + +LOCAL_MODULE_FILENAME := libbox2d + +LOCAL_SRC_FILES := \ +Collision/b2BroadPhase.cpp \ +Collision/b2CollideCircle.cpp \ +Collision/b2CollideEdge.cpp \ +Collision/b2CollidePolygon.cpp \ +Collision/b2Collision.cpp \ +Collision/b2Distance.cpp \ +Collision/b2DynamicTree.cpp \ +Collision/b2TimeOfImpact.cpp \ +Collision/Shapes/b2ChainShape.cpp \ +Collision/Shapes/b2CircleShape.cpp \ +Collision/Shapes/b2EdgeShape.cpp \ +Collision/Shapes/b2PolygonShape.cpp \ +Common/b2BlockAllocator.cpp \ +Common/b2Draw.cpp \ +Common/b2Math.cpp \ +Common/b2Settings.cpp \ +Common/b2StackAllocator.cpp \ +Common/b2Timer.cpp \ +Dynamics/b2Body.cpp \ +Dynamics/b2ContactManager.cpp \ +Dynamics/b2Fixture.cpp \ +Dynamics/b2Island.cpp \ +Dynamics/b2World.cpp \ +Dynamics/b2WorldCallbacks.cpp \ +Dynamics/Contacts/b2ChainAndCircleContact.cpp \ +Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ +Dynamics/Contacts/b2CircleContact.cpp \ +Dynamics/Contacts/b2Contact.cpp \ +Dynamics/Contacts/b2ContactSolver.cpp \ +Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ +Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ +Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ +Dynamics/Contacts/b2PolygonContact.cpp \ +Dynamics/Joints/b2DistanceJoint.cpp \ +Dynamics/Joints/b2FrictionJoint.cpp \ +Dynamics/Joints/b2GearJoint.cpp \ +Dynamics/Joints/b2Joint.cpp \ +Dynamics/Joints/b2MouseJoint.cpp \ +Dynamics/Joints/b2PrismaticJoint.cpp \ +Dynamics/Joints/b2PulleyJoint.cpp \ +Dynamics/Joints/b2RevoluteJoint.cpp \ +Dynamics/Joints/b2RopeJoint.cpp \ +Dynamics/Joints/b2WeldJoint.cpp \ +Dynamics/Joints/b2WheelJoint.cpp \ +Rope/b2Rope.cpp + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. + +include $(BUILD_STATIC_LIBRARY) diff --git a/external/Box2D/Box2D.h b/external/Box2D/Box2D.h new file mode 100644 index 0000000000..f674d82269 --- /dev/null +++ b/external/Box2D/Box2D.h @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef BOX2D_H +#define BOX2D_H + +/** +\mainpage Box2D API Documentation + +\section intro_sec Getting Started + +For documentation please see http://box2d.org/documentation.html + +For discussion please visit http://box2d.org/forum +*/ + +// These include files constitute the main Box2D API + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/external/Box2D/Collision/Shapes/b2ChainShape.cpp b/external/Box2D/Collision/Shapes/b2ChainShape.cpp new file mode 100644 index 0000000000..79b4304b5b --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2ChainShape.cpp @@ -0,0 +1,171 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +using namespace std; + +b2ChainShape::~b2ChainShape() +{ + b2Free(m_vertices); + m_vertices = NULL; + m_count = 0; +} + +void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 3); + m_count = count + 1; + m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); + m_vertices[count] = m_vertices[0]; + m_prevVertex = m_vertices[m_count - 2]; + m_nextVertex = m_vertices[1]; + m_hasPrevVertex = true; + m_hasNextVertex = true; +} + +void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) +{ + b2Assert(m_vertices == NULL && m_count == 0); + b2Assert(count >= 2); + m_count = count; + m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); + memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) +{ + m_prevVertex = prevVertex; + m_hasPrevVertex = true; +} + +void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) +{ + m_nextVertex = nextVertex; + m_hasNextVertex = true; +} + +b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2ChainShape)); + b2ChainShape* clone = new (mem) b2ChainShape; + clone->CreateChain(m_vertices, m_count); + clone->m_prevVertex = m_prevVertex; + clone->m_nextVertex = m_nextVertex; + clone->m_hasPrevVertex = m_hasPrevVertex; + clone->m_hasNextVertex = m_hasNextVertex; + return clone; +} + +int32 b2ChainShape::GetChildCount() const +{ + // edge count = vertex count - 1 + return m_count - 1; +} + +void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const +{ + b2Assert(0 <= index && index < m_count - 1); + edge->m_type = b2Shape::e_edge; + edge->m_radius = m_radius; + + edge->m_vertex1 = m_vertices[index + 0]; + edge->m_vertex2 = m_vertices[index + 1]; + + if (index > 0) + { + edge->m_vertex0 = m_vertices[index - 1]; + edge->m_hasVertex0 = true; + } + else + { + edge->m_vertex0 = m_prevVertex; + edge->m_hasVertex0 = m_hasPrevVertex; + } + + if (index < m_count - 2) + { + edge->m_vertex3 = m_vertices[index + 2]; + edge->m_hasVertex3 = true; + } + else + { + edge->m_vertex3 = m_nextVertex; + edge->m_hasVertex3 = m_hasNextVertex; + } +} + +bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + b2EdgeShape edgeShape; + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + edgeShape.m_vertex1 = m_vertices[i1]; + edgeShape.m_vertex2 = m_vertices[i2]; + + return edgeShape.RayCast(output, input, xf, 0); +} + +void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + b2Assert(childIndex < m_count); + + int32 i1 = childIndex; + int32 i2 = childIndex + 1; + if (i2 == m_count) + { + i2 = 0; + } + + b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); + b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); + + aabb->lowerBound = b2Min(v1, v2); + aabb->upperBound = b2Max(v1, v2); +} + +void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center.SetZero(); + massData->I = 0.0f; +} diff --git a/external/Box2D/Collision/Shapes/b2ChainShape.h b/external/Box2D/Collision/Shapes/b2ChainShape.h new file mode 100644 index 0000000000..9c9a9eaa7d --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2ChainShape.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2006-2010 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. +*/ + +#ifndef B2_CHAIN_SHAPE_H +#define B2_CHAIN_SHAPE_H + +#include + +class b2EdgeShape; + +/// A chain shape is a free form sequence of line segments. +/// The chain has two-sided collision, so you can use inside and outside collision. +/// Therefore, you may use any winding order. +/// Since there may be many vertices, they are allocated using b2Alloc. +/// Connectivity information is used to create smooth collisions. +/// WARNING: The chain will not collide properly if there are self-intersections. +class b2ChainShape : public b2Shape +{ +public: + b2ChainShape(); + + /// The destructor frees the vertices using b2Free. + ~b2ChainShape(); + + /// Create a loop. This automatically adjusts connectivity. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateLoop(const b2Vec2* vertices, int32 count); + + /// Create a chain with isolated end vertices. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateChain(const b2Vec2* vertices, int32 count); + + /// Establish connectivity to a vertex that precedes the first vertex. + /// Don't call this for loops. + void SetPrevVertex(const b2Vec2& prevVertex); + + /// Establish connectivity to a vertex that follows the last vertex. + /// Don't call this for loops. + void SetNextVertex(const b2Vec2& nextVertex); + + /// Implement b2Shape. Vertices are cloned using b2Alloc. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Get a child edge. + void GetChildEdge(b2EdgeShape* edge, int32 index) const; + + /// This always return false. + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// Chains have zero mass. + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// The vertices. Owned by this class. + b2Vec2* m_vertices; + + /// The vertex count. + int32 m_count; + + b2Vec2 m_prevVertex, m_nextVertex; + bool m_hasPrevVertex, m_hasNextVertex; +}; + +inline b2ChainShape::b2ChainShape() +{ + m_type = e_chain; + m_radius = b2_polygonRadius; + m_vertices = NULL; + m_count = 0; + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +#endif diff --git a/external/Box2D/Collision/Shapes/b2CircleShape.cpp b/external/Box2D/Collision/Shapes/b2CircleShape.cpp new file mode 100644 index 0000000000..587ca960b2 --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2CircleShape.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2006-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 +#include +using namespace std; + +b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2CircleShape)); + b2CircleShape* clone = new (mem) b2CircleShape; + *clone = *this; + return clone; +} + +int32 b2CircleShape::GetChildCount() const +{ + return 1; +} + +bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const +{ + b2Vec2 center = transform.p + b2Mul(transform.q, m_p); + b2Vec2 d = p - center; + return b2Dot(d, d) <= m_radius * m_radius; +} + +// Collision Detection in Interactive 3D Environments by Gino van den Bergen +// From Section 3.1.2 +// x = s + a * r +// norm(x) = radius +bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 position = transform.p + b2Mul(transform.q, m_p); + b2Vec2 s = input.p1 - position; + float32 b = b2Dot(s, s) - m_radius * m_radius; + + // Solve quadratic equation. + b2Vec2 r = input.p2 - input.p1; + float32 c = b2Dot(s, r); + float32 rr = b2Dot(r, r); + float32 sigma = c * c - rr * b; + + // Check for negative discriminant and short segment. + if (sigma < 0.0f || rr < b2_epsilon) + { + return false; + } + + // Find the point of intersection of the line with the circle. + float32 a = -(c + b2Sqrt(sigma)); + + // Is the intersection point on the segment? + if (0.0f <= a && a <= input.maxFraction * rr) + { + a /= rr; + output->fraction = a; + output->normal = s + a * r; + output->normal.Normalize(); + return true; + } + + return false; +} + +void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 p = transform.p + b2Mul(transform.q, m_p); + aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); + aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); +} + +void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const +{ + massData->mass = density * b2_pi * m_radius * m_radius; + massData->center = m_p; + + // inertia about the local origin + massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); +} diff --git a/external/Box2D/Collision/Shapes/b2CircleShape.h b/external/Box2D/Collision/Shapes/b2CircleShape.h new file mode 100644 index 0000000000..c4e23a475b --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2CircleShape.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CIRCLE_SHAPE_H +#define B2_CIRCLE_SHAPE_H + +#include + +/// A circle shape. +class b2CircleShape : public b2Shape +{ +public: + b2CircleShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Implement b2Shape. + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return 1; } + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + /// Position + b2Vec2 m_p; +}; + +inline b2CircleShape::b2CircleShape() +{ + m_type = e_circle; + m_radius = 0.0f; + m_p.SetZero(); +} + +inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return 0; +} + +inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return m_p; +} + +inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const +{ + B2_NOT_USED(index); + b2Assert(index == 0); + return m_p; +} + +#endif diff --git a/external/Box2D/Collision/Shapes/b2EdgeShape.cpp b/external/Box2D/Collision/Shapes/b2EdgeShape.cpp new file mode 100644 index 0000000000..7b09e55bf4 --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2EdgeShape.cpp @@ -0,0 +1,139 @@ +/* +* Copyright (c) 2006-2010 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 +#include +using namespace std; + +void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) +{ + m_vertex1 = v1; + m_vertex2 = v2; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2EdgeShape)); + b2EdgeShape* clone = new (mem) b2EdgeShape; + *clone = *this; + return clone; +} + +int32 b2EdgeShape::GetChildCount() const +{ + return 1; +} + +bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + B2_NOT_USED(xf); + B2_NOT_USED(p); + return false; +} + +// p = p1 + t * d +// v = v1 + s * e +// p1 + t * d = v1 + s * e +// s * e - t * d = p1 - v1 +bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the edge's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + b2Vec2 v1 = m_vertex1; + b2Vec2 v2 = m_vertex2; + b2Vec2 e = v2 - v1; + b2Vec2 normal(e.y, -e.x); + normal.Normalize(); + + // q = p1 + t * d + // dot(normal, q - v1) = 0 + // dot(normal, p1 - v1) + t * dot(normal, d) = 0 + float32 numerator = b2Dot(normal, v1 - p1); + float32 denominator = b2Dot(normal, d); + + if (denominator == 0.0f) + { + return false; + } + + float32 t = numerator / denominator; + if (t < 0.0f || input.maxFraction < t) + { + return false; + } + + b2Vec2 q = p1 + t * d; + + // q = v1 + s * r + // s = dot(q - v1, r) / dot(r, r) + b2Vec2 r = v2 - v1; + float32 rr = b2Dot(r, r); + if (rr == 0.0f) + { + return false; + } + + float32 s = b2Dot(q - v1, r) / rr; + if (s < 0.0f || 1.0f < s) + { + return false; + } + + output->fraction = t; + if (numerator > 0.0f) + { + output->normal = -normal; + } + else + { + output->normal = normal; + } + return true; +} + +void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 v1 = b2Mul(xf, m_vertex1); + b2Vec2 v2 = b2Mul(xf, m_vertex2); + + b2Vec2 lower = b2Min(v1, v2); + b2Vec2 upper = b2Max(v1, v2); + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const +{ + B2_NOT_USED(density); + + massData->mass = 0.0f; + massData->center = 0.5f * (m_vertex1 + m_vertex2); + massData->I = 0.0f; +} diff --git a/external/Box2D/Collision/Shapes/b2EdgeShape.h b/external/Box2D/Collision/Shapes/b2EdgeShape.h new file mode 100644 index 0000000000..6163bcbf1c --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2EdgeShape.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2006-2010 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. +*/ + +#ifndef B2_EDGE_SHAPE_H +#define B2_EDGE_SHAPE_H + +#include + +/// A line segment (edge) shape. These can be connected in chains or loops +/// to other edge shapes. The connectivity information is used to ensure +/// correct contact normals. +class b2EdgeShape : public b2Shape +{ +public: + b2EdgeShape(); + + /// Set this as an isolated edge. + void Set(const b2Vec2& v1, const b2Vec2& v2); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// These are the edge vertices + b2Vec2 m_vertex1, m_vertex2; + + /// Optional adjacent vertices. These are used for smooth collision. + b2Vec2 m_vertex0, m_vertex3; + bool m_hasVertex0, m_hasVertex3; +}; + +inline b2EdgeShape::b2EdgeShape() +{ + m_type = e_edge; + m_radius = b2_polygonRadius; + m_vertex0.x = 0.0f; + m_vertex0.y = 0.0f; + m_vertex3.x = 0.0f; + m_vertex3.y = 0.0f; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +#endif diff --git a/external/Box2D/Collision/Shapes/b2PolygonShape.cpp b/external/Box2D/Collision/Shapes/b2PolygonShape.cpp new file mode 100644 index 0000000000..c04c1dc49b --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2PolygonShape.cpp @@ -0,0 +1,361 @@ +/* +* Copyright (c) 2006-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 +#include + +b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const +{ + void* mem = allocator->Allocate(sizeof(b2PolygonShape)); + b2PolygonShape* clone = new (mem) b2PolygonShape; + *clone = *this; + return clone; +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid.SetZero(); +} + +void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) +{ + m_vertexCount = 4; + m_vertices[0].Set(-hx, -hy); + m_vertices[1].Set( hx, -hy); + m_vertices[2].Set( hx, hy); + m_vertices[3].Set(-hx, hy); + m_normals[0].Set(0.0f, -1.0f); + m_normals[1].Set(1.0f, 0.0f); + m_normals[2].Set(0.0f, 1.0f); + m_normals[3].Set(-1.0f, 0.0f); + m_centroid = center; + + b2Transform xf; + xf.p = center; + xf.q.Set(angle); + + // Transform vertices and normals. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = b2Mul(xf, m_vertices[i]); + m_normals[i] = b2Mul(xf.q, m_normals[i]); + } +} + +int32 b2PolygonShape::GetChildCount() const +{ + return 1; +} + +static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) +{ + b2Assert(count >= 3); + + b2Vec2 c; c.Set(0.0f, 0.0f); + float32 area = 0.0f; + + // pRef is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 pRef(0.0f, 0.0f); +#if 0 + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < count; ++i) + { + pRef += vs[i]; + } + pRef *= 1.0f / count; +#endif + + const float32 inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < count; ++i) + { + // Triangle vertices. + b2Vec2 p1 = pRef; + b2Vec2 p2 = vs[i]; + b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; + + b2Vec2 e1 = p2 - p1; + b2Vec2 e2 = p3 - p1; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + c += triangleArea * inv3 * (p1 + p2 + p3); + } + + // Centroid + b2Assert(area > b2_epsilon); + c *= 1.0f / area; + return c; +} + +void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) +{ + b2Assert(3 <= count && count <= b2_maxPolygonVertices); + m_vertexCount = count; + + // Copy vertices. + for (int32 i = 0; i < m_vertexCount; ++i) + { + m_vertices[i] = vertices[i]; + } + + // Compute normals. Ensure the edges have non-zero length. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); + m_normals[i] = b2Cross(edge, 1.0f); + m_normals[i].Normalize(); + } + +#ifdef _DEBUG + // Ensure the polygon is convex and the interior + // is to the left of each edge. + for (int32 i = 0; i < m_vertexCount; ++i) + { + int32 i1 = i; + int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; + b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; + + for (int32 j = 0; j < m_vertexCount; ++j) + { + // Don't check vertices on the current edge. + if (j == i1 || j == i2) + { + continue; + } + + b2Vec2 r = m_vertices[j] - m_vertices[i1]; + + // If this crashes, your polygon is non-convex, has colinear edges, + // or the winding order is wrong. + float32 s = b2Cross(edge, r); + b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order"); + } + } +#endif + + // Compute the polygon centroid. + m_centroid = ComputeCentroid(m_vertices, m_vertexCount); +} + +bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const +{ + b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); + + for (int32 i = 0; i < m_vertexCount; ++i) + { + float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); + if (dot > 0.0f) + { + return false; + } + } + + return true; +} + +bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + // Put the ray into the polygon's frame of reference. + b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); + b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); + b2Vec2 d = p2 - p1; + + float32 lower = 0.0f, upper = input.maxFraction; + + int32 index = -1; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // p = p1 + a * d + // dot(normal, p - v) = 0 + // dot(normal, p1 - v) + a * dot(normal, d) = 0 + float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); + float32 denominator = b2Dot(m_normals[i], d); + + if (denominator == 0.0f) + { + if (numerator < 0.0f) + { + return false; + } + } + else + { + // Note: we want this predicate without division: + // lower < numerator / denominator, where denominator < 0 + // Since denominator < 0, we have to flip the inequality: + // lower < numerator / denominator <==> denominator * lower > numerator. + if (denominator < 0.0f && numerator < lower * denominator) + { + // Increase lower. + // The segment enters this half-space. + lower = numerator / denominator; + index = i; + } + else if (denominator > 0.0f && numerator < upper * denominator) + { + // Decrease upper. + // The segment exits this half-space. + upper = numerator / denominator; + } + } + + // The use of epsilon here causes the assert on lower to trip + // in some cases. Apparently the use of epsilon was to make edge + // shapes work, but now those are handled separately. + //if (upper < lower - b2_epsilon) + if (upper < lower) + { + return false; + } + } + + b2Assert(0.0f <= lower && lower <= input.maxFraction); + + if (index >= 0) + { + output->fraction = lower; + output->normal = b2Mul(xf.q, m_normals[index]); + return true; + } + + return false; +} + +void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const +{ + B2_NOT_USED(childIndex); + + b2Vec2 lower = b2Mul(xf, m_vertices[0]); + b2Vec2 upper = lower; + + for (int32 i = 1; i < m_vertexCount; ++i) + { + b2Vec2 v = b2Mul(xf, m_vertices[i]); + lower = b2Min(lower, v); + upper = b2Max(upper, v); + } + + b2Vec2 r(m_radius, m_radius); + aabb->lowerBound = lower - r; + aabb->upperBound = upper + r; +} + +void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const +{ + // Polygon mass, centroid, and inertia. + // Let rho be the polygon density in mass per unit area. + // Then: + // mass = rho * int(dA) + // centroid.x = (1/mass) * rho * int(x * dA) + // centroid.y = (1/mass) * rho * int(y * dA) + // I = rho * int((x*x + y*y) * dA) + // + // We can compute these integrals by summing all the integrals + // for each triangle of the polygon. To evaluate the integral + // for a single triangle, we make a change of variables to + // the (u,v) coordinates of the triangle: + // x = x0 + e1x * u + e2x * v + // y = y0 + e1y * u + e2y * v + // where 0 <= u && 0 <= v && u + v <= 1. + // + // We integrate u from [0,1-v] and then v from [0,1]. + // We also need to use the Jacobian of the transformation: + // D = cross(e1, e2) + // + // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) + // + // The rest of the derivation is handled by computer algebra. + + b2Assert(m_vertexCount >= 3); + + b2Vec2 center; center.Set(0.0f, 0.0f); + float32 area = 0.0f; + float32 I = 0.0f; + + // s is the reference point for forming triangles. + // It's location doesn't change the result (except for rounding error). + b2Vec2 s(0.0f, 0.0f); + + // This code would put the reference point inside the polygon. + for (int32 i = 0; i < m_vertexCount; ++i) + { + s += m_vertices[i]; + } + s *= 1.0f / m_vertexCount; + + const float32 k_inv3 = 1.0f / 3.0f; + + for (int32 i = 0; i < m_vertexCount; ++i) + { + // Triangle vertices. + b2Vec2 e1 = m_vertices[i] - s; + b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s; + + float32 D = b2Cross(e1, e2); + + float32 triangleArea = 0.5f * D; + area += triangleArea; + + // Area weighted centroid + center += triangleArea * k_inv3 * (e1 + e2); + + float32 ex1 = e1.x, ey1 = e1.y; + float32 ex2 = e2.x, ey2 = e2.y; + + float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; + float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; + + I += (0.25f * k_inv3 * D) * (intx2 + inty2); + } + + // Total mass + massData->mass = density * area; + + // Center of mass + b2Assert(area > b2_epsilon); + center *= 1.0f / area; + massData->center = center + s; + + // Inertia tensor relative to the local origin (point s). + massData->I = density * I; + + // Shift to center of mass then to original body origin. + massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); +} diff --git a/external/Box2D/Collision/Shapes/b2PolygonShape.h b/external/Box2D/Collision/Shapes/b2PolygonShape.h new file mode 100644 index 0000000000..70daccb2ff --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2PolygonShape.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_SHAPE_H +#define B2_POLYGON_SHAPE_H + +#include + +/// A convex polygon. It is assumed that the interior of the polygon is to +/// the left of each edge. +/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. +/// In most cases you should not need many vertices for a convex polygon. +class b2PolygonShape : public b2Shape +{ +public: + b2PolygonShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Copy vertices. This assumes the vertices define a convex polygon. + /// It is assumed that the exterior is the the right of each edge. + /// The count must be in the range [3, b2_maxPolygonVertices]. + void Set(const b2Vec2* vertices, int32 vertexCount); + + /// Build vertices to represent an axis-aligned box. + /// @param hx the half-width. + /// @param hy the half-height. + void SetAsBox(float32 hx, float32 hy); + + /// Build vertices to represent an oriented box. + /// @param hx the half-width. + /// @param hy the half-height. + /// @param center the center of the box in local coordinates. + /// @param angle the rotation of the box in local coordinates. + void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return m_vertexCount; } + + /// Get a vertex by index. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_centroid; + b2Vec2 m_vertices[b2_maxPolygonVertices]; + b2Vec2 m_normals[b2_maxPolygonVertices]; + int32 m_vertexCount; +}; + +inline b2PolygonShape::b2PolygonShape() +{ + m_type = e_polygon; + m_radius = b2_polygonRadius; + m_vertexCount = 0; + m_centroid.SetZero(); +} + +inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_vertexCount); + return m_vertices[index]; +} + +#endif diff --git a/external/Box2D/Collision/Shapes/b2Shape.h b/external/Box2D/Collision/Shapes/b2Shape.h new file mode 100644 index 0000000000..2e2aedd14a --- /dev/null +++ b/external/Box2D/Collision/Shapes/b2Shape.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_SHAPE_H +#define B2_SHAPE_H + +#include +#include +#include + +/// This holds the mass data computed for a shape. +struct b2MassData +{ + /// The mass of the shape, usually in kilograms. + float32 mass; + + /// The position of the shape's centroid relative to the shape's origin. + b2Vec2 center; + + /// The rotational inertia of the shape about the local origin. + float32 I; +}; + +/// A shape is used for collision detection. You can create a shape however you like. +/// Shapes used for simulation in b2World are created automatically when a b2Fixture +/// is created. Shapes may encapsulate a one or more child shapes. +class b2Shape +{ +public: + + enum Type + { + e_circle = 0, + e_edge = 1, + e_polygon = 2, + e_chain = 3, + e_typeCount = 4 + }; + + virtual ~b2Shape() {} + + /// Clone the concrete shape using the provided allocator. + virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; + + /// Get the type of this shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + Type GetType() const; + + /// Get the number of child primitives. + virtual int32 GetChildCount() const = 0; + + /// Test a point for containment in this shape. This only works for convex shapes. + /// @param xf the shape world transform. + /// @param p a point in world coordinates. + virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; + + /// Cast a ray against a child shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + /// @param transform the transform to be applied to the shape. + /// @param childIndex the child shape index + virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const = 0; + + /// Given a transform, compute the associated axis aligned bounding box for a child shape. + /// @param aabb returns the axis aligned box. + /// @param xf the world transform of the shape. + /// @param childIndex the child shape + virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; + + /// Compute the mass properties of this shape using its dimensions and density. + /// The inertia tensor is computed about the local origin. + /// @param massData returns the mass data for this shape. + /// @param density the density in kilograms per meter squared. + virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; + + Type m_type; + float32 m_radius; +}; + +inline b2Shape::Type b2Shape::GetType() const +{ + return m_type; +} + +#endif diff --git a/external/Box2D/Collision/b2BroadPhase.cpp b/external/Box2D/Collision/b2BroadPhase.cpp new file mode 100644 index 0000000000..431f6de1ee --- /dev/null +++ b/external/Box2D/Collision/b2BroadPhase.cpp @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2006-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 +#include +using namespace std; + +b2BroadPhase::b2BroadPhase() +{ + m_proxyCount = 0; + + m_pairCapacity = 16; + m_pairCount = 0; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + + m_moveCapacity = 16; + m_moveCount = 0; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); +} + +b2BroadPhase::~b2BroadPhase() +{ + b2Free(m_moveBuffer); + b2Free(m_pairBuffer); +} + +int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = m_tree.CreateProxy(aabb, userData); + ++m_proxyCount; + BufferMove(proxyId); + return proxyId; +} + +void b2BroadPhase::DestroyProxy(int32 proxyId) +{ + UnBufferMove(proxyId); + --m_proxyCount; + m_tree.DestroyProxy(proxyId); +} + +void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); + if (buffer) + { + BufferMove(proxyId); + } +} + +void b2BroadPhase::TouchProxy(int32 proxyId) +{ + BufferMove(proxyId); +} + +void b2BroadPhase::BufferMove(int32 proxyId) +{ + if (m_moveCount == m_moveCapacity) + { + int32* oldBuffer = m_moveBuffer; + m_moveCapacity *= 2; + m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); + memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); + b2Free(oldBuffer); + } + + m_moveBuffer[m_moveCount] = proxyId; + ++m_moveCount; +} + +void b2BroadPhase::UnBufferMove(int32 proxyId) +{ + for (int32 i = 0; i < m_moveCount; ++i) + { + if (m_moveBuffer[i] == proxyId) + { + m_moveBuffer[i] = e_nullProxy; + return; + } + } +} + +// This is called from b2DynamicTree::Query when we are gathering pairs. +bool b2BroadPhase::QueryCallback(int32 proxyId) +{ + // A proxy cannot form a pair with itself. + if (proxyId == m_queryProxyId) + { + return true; + } + + // Grow the pair buffer as needed. + if (m_pairCount == m_pairCapacity) + { + b2Pair* oldBuffer = m_pairBuffer; + m_pairCapacity *= 2; + m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); + memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); + b2Free(oldBuffer); + } + + m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); + m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); + ++m_pairCount; + + return true; +} diff --git a/external/Box2D/Collision/b2BroadPhase.h b/external/Box2D/Collision/b2BroadPhase.h new file mode 100644 index 0000000000..cf2414730a --- /dev/null +++ b/external/Box2D/Collision/b2BroadPhase.h @@ -0,0 +1,248 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_BROAD_PHASE_H +#define B2_BROAD_PHASE_H + +#include +#include +#include +#include + +struct b2Pair +{ + int32 proxyIdA; + int32 proxyIdB; + int32 next; +}; + +/// The broad-phase is used for computing pairs and performing volume queries and ray casts. +/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. +/// It is up to the client to consume the new pairs and to track subsequent overlap. +class b2BroadPhase +{ +public: + + enum + { + e_nullProxy = -1 + }; + + b2BroadPhase(); + ~b2BroadPhase(); + + /// Create a proxy with an initial AABB. Pairs are not reported until + /// UpdatePairs is called. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. It is up to the client to remove any pairs. + void DestroyProxy(int32 proxyId); + + /// Call MoveProxy as many times as you like, then when you are done + /// call UpdatePairs to finalized the proxy pairs (for your time step). + void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); + + /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. + void TouchProxy(int32 proxyId); + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Get user data from a proxy. Returns NULL if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Test overlap of fat AABBs. + bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; + + /// Get the number of proxies. + int32 GetProxyCount() const; + + /// Update the pairs. This results in pair callbacks. This can only add pairs. + template + void UpdatePairs(T* callback); + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Get the height of the embedded tree. + int32 GetTreeHeight() const; + + /// Get the balance of the embedded tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the embedded tree. + float32 GetTreeQuality() const; + +private: + + friend class b2DynamicTree; + + void BufferMove(int32 proxyId); + void UnBufferMove(int32 proxyId); + + bool QueryCallback(int32 proxyId); + + b2DynamicTree m_tree; + + int32 m_proxyCount; + + int32* m_moveBuffer; + int32 m_moveCapacity; + int32 m_moveCount; + + b2Pair* m_pairBuffer; + int32 m_pairCapacity; + int32 m_pairCount; + + int32 m_queryProxyId; +}; + +/// This is used to sort pairs. +inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) +{ + if (pair1.proxyIdA < pair2.proxyIdA) + { + return true; + } + + if (pair1.proxyIdA == pair2.proxyIdA) + { + return pair1.proxyIdB < pair2.proxyIdB; + } + + return false; +} + +inline void* b2BroadPhase::GetUserData(int32 proxyId) const +{ + return m_tree.GetUserData(proxyId); +} + +inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const +{ + const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); + const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); + return b2TestOverlap(aabbA, aabbB); +} + +inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const +{ + return m_tree.GetFatAABB(proxyId); +} + +inline int32 b2BroadPhase::GetProxyCount() const +{ + return m_proxyCount; +} + +inline int32 b2BroadPhase::GetTreeHeight() const +{ + return m_tree.GetHeight(); +} + +inline int32 b2BroadPhase::GetTreeBalance() const +{ + return m_tree.GetMaxBalance(); +} + +inline float32 b2BroadPhase::GetTreeQuality() const +{ + return m_tree.GetAreaRatio(); +} + +template +void b2BroadPhase::UpdatePairs(T* callback) +{ + // Reset pair buffer + m_pairCount = 0; + + // Perform tree queries for all moving proxies. + for (int32 i = 0; i < m_moveCount; ++i) + { + m_queryProxyId = m_moveBuffer[i]; + if (m_queryProxyId == e_nullProxy) + { + continue; + } + + // We have to query the tree with the fat AABB so that + // we don't fail to create a pair that may touch later. + const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); + + // Query tree, create pairs and add them pair buffer. + m_tree.Query(this, fatAABB); + } + + // Reset move buffer + m_moveCount = 0; + + // Sort the pair buffer to expose duplicates. + std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); + + // Send the pairs back to the client. + int32 i = 0; + while (i < m_pairCount) + { + b2Pair* primaryPair = m_pairBuffer + i; + void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); + void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); + + callback->AddPair(userDataA, userDataB); + ++i; + + // Skip any duplicate pairs. + while (i < m_pairCount) + { + b2Pair* pair = m_pairBuffer + i; + if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) + { + break; + } + ++i; + } + } + + // Try to keep the tree balanced. + //m_tree.Rebalance(4); +} + +template +inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const +{ + m_tree.Query(callback, aabb); +} + +template +inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const +{ + m_tree.RayCast(callback, input); +} + +#endif diff --git a/external/Box2D/Collision/b2CollideCircle.cpp b/external/Box2D/Collision/b2CollideCircle.cpp new file mode 100644 index 0000000000..ed561eb04b --- /dev/null +++ b/external/Box2D/Collision/b2CollideCircle.cpp @@ -0,0 +1,154 @@ +/* +* 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 +#include +#include + +void b2CollideCircles( + b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + b2Vec2 pA = b2Mul(xfA, circleA->m_p); + b2Vec2 pB = b2Mul(xfB, circleB->m_p); + + b2Vec2 d = pB - pA; + float32 distSqr = b2Dot(d, d); + float32 rA = circleA->m_radius, rB = circleB->m_radius; + float32 radius = rA + rB; + if (distSqr > radius * radius) + { + return; + } + + manifold->type = b2Manifold::e_circles; + manifold->localPoint = circleA->m_p; + manifold->localNormal.SetZero(); + manifold->pointCount = 1; + + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; +} + +void b2CollidePolygonAndCircle( + b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + + // Compute circle position in the frame of the polygon. + b2Vec2 c = b2Mul(xfB, circleB->m_p); + b2Vec2 cLocal = b2MulT(xfA, c); + + // Find the min separating edge. + int32 normalIndex = 0; + float32 separation = -b2_maxFloat; + float32 radius = polygonA->m_radius + circleB->m_radius; + int32 vertexCount = polygonA->m_vertexCount; + const b2Vec2* vertices = polygonA->m_vertices; + const b2Vec2* normals = polygonA->m_normals; + + for (int32 i = 0; i < vertexCount; ++i) + { + float32 s = b2Dot(normals[i], cLocal - vertices[i]); + + if (s > radius) + { + // Early out. + return; + } + + if (s > separation) + { + separation = s; + normalIndex = i; + } + } + + // Vertices that subtend the incident face. + int32 vertIndex1 = normalIndex; + int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; + b2Vec2 v1 = vertices[vertIndex1]; + b2Vec2 v2 = vertices[vertIndex2]; + + // If the center is inside the polygon ... + if (separation < b2_epsilon) + { + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[normalIndex]; + manifold->localPoint = 0.5f * (v1 + v2); + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + return; + } + + // Compute barycentric coordinates + float32 u1 = b2Dot(cLocal - v1, v2 - v1); + float32 u2 = b2Dot(cLocal - v2, v1 - v2); + if (u1 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v1) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v1; + manifold->localNormal.Normalize(); + manifold->localPoint = v1; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else if (u2 <= 0.0f) + { + if (b2DistanceSquared(cLocal, v2) > radius * radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = cLocal - v2; + manifold->localNormal.Normalize(); + manifold->localPoint = v2; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } + else + { + b2Vec2 faceCenter = 0.5f * (v1 + v2); + float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); + if (separation > radius) + { + return; + } + + manifold->pointCount = 1; + manifold->type = b2Manifold::e_faceA; + manifold->localNormal = normals[vertIndex1]; + manifold->localPoint = faceCenter; + manifold->points[0].localPoint = circleB->m_p; + manifold->points[0].id.key = 0; + } +} diff --git a/external/Box2D/Collision/b2CollideEdge.cpp b/external/Box2D/Collision/b2CollideEdge.cpp new file mode 100644 index 0000000000..96ca71dccc --- /dev/null +++ b/external/Box2D/Collision/b2CollideEdge.cpp @@ -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 +#include +#include +#include + + +// 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 hasVertex3F = 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 (hasVertex3F) + { + 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 && hasVertex3F) + { + 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 (hasVertex3F) + { + 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 = 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 = 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 = 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 = 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); +} diff --git a/external/Box2D/Collision/b2CollidePolygon.cpp b/external/Box2D/Collision/b2CollidePolygon.cpp new file mode 100644 index 0000000000..be2518d966 --- /dev/null +++ b/external/Box2D/Collision/b2CollidePolygon.cpp @@ -0,0 +1,317 @@ +/* +* Copyright (c) 2006-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 +#include + +// Find the separation between poly1 and poly2 for a give edge normal on poly1. +static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* vertices1 = poly1->m_vertices; + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Convert normal from poly1's frame into poly2's frame. + b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); + b2Vec2 normal1 = b2MulT(xf2.q, normal1World); + + // Find support vertex on poly2 for -normal. + int32 index = 0; + float32 minDot = b2_maxFloat; + + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(vertices2[i], normal1); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); + b2Vec2 v2 = b2Mul(xf2, vertices2[index]); + float32 separation = b2Dot(v2 - v1, normal1World); + return separation; +} + +// Find the max separation between poly1 and poly2 using edge normals from poly1. +static float32 b2FindMaxSeparation(int32* edgeIndex, + const b2PolygonShape* poly1, const b2Transform& xf1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + int32 count1 = poly1->m_vertexCount; + const b2Vec2* normals1 = poly1->m_normals; + + // Vector pointing from the centroid of poly1 to the centroid of poly2. + b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); + b2Vec2 dLocal1 = b2MulT(xf1.q, d); + + // Find edge normal on poly1 that has the largest projection onto d. + int32 edge = 0; + float32 maxDot = -b2_maxFloat; + for (int32 i = 0; i < count1; ++i) + { + float32 dot = b2Dot(normals1[i], dLocal1); + if (dot > maxDot) + { + maxDot = dot; + edge = i; + } + } + + // Get the separation for the edge normal. + float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + // Check the separation for the previous edge normal. + int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; + float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + + // Check the separation for the next edge normal. + int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; + float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + + // Find the best edge and the search direction. + int32 bestEdge; + float32 bestSeparation; + int32 increment; + if (sPrev > s && sPrev > sNext) + { + increment = -1; + bestEdge = prevEdge; + bestSeparation = sPrev; + } + else if (sNext > s) + { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext; + } + else + { + *edgeIndex = edge; + return s; + } + + // Perform a local search for the best edge normal. + for ( ; ; ) + { + if (increment == -1) + edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; + else + edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; + + s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); + + if (s > bestSeparation) + { + bestEdge = edge; + bestSeparation = s; + } + else + { + break; + } + } + + *edgeIndex = bestEdge; + return bestSeparation; +} + +static void b2FindIncidentEdge(b2ClipVertex c[2], + const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, + const b2PolygonShape* poly2, const b2Transform& xf2) +{ + const b2Vec2* normals1 = poly1->m_normals; + + int32 count2 = poly2->m_vertexCount; + const b2Vec2* vertices2 = poly2->m_vertices; + const b2Vec2* normals2 = poly2->m_normals; + + b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount); + + // Get the normal of the reference edge in poly2's frame. + b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); + + // Find the incident edge on poly2. + int32 index = 0; + float32 minDot = b2_maxFloat; + for (int32 i = 0; i < count2; ++i) + { + float32 dot = b2Dot(normal1, normals2[i]); + if (dot < minDot) + { + minDot = dot; + index = i; + } + } + + // Build the clip vertices for the incident edge. + int32 i1 = index; + int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; + + c[0].v = b2Mul(xf2, vertices2[i1]); + c[0].id.cf.indexA = (uint8)edge1; + c[0].id.cf.indexB = (uint8)i1; + c[0].id.cf.typeA = b2ContactFeature::e_face; + c[0].id.cf.typeB = b2ContactFeature::e_vertex; + + c[1].v = b2Mul(xf2, vertices2[i2]); + c[1].id.cf.indexA = (uint8)edge1; + c[1].id.cf.indexB = (uint8)i2; + c[1].id.cf.typeA = b2ContactFeature::e_face; + c[1].id.cf.typeB = b2ContactFeature::e_vertex; +} + +// Find edge normal of max separation on A - return if separating axis is found +// Find edge normal of max separation on B - return if separation axis is found +// Choose reference edge as min(minA, minB) +// Find incident edge +// Clip + +// The normal points from 1 to 2 +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polyA, const b2Transform& xfA, + const b2PolygonShape* polyB, const b2Transform& xfB) +{ + manifold->pointCount = 0; + float32 totalRadius = polyA->m_radius + polyB->m_radius; + + int32 edgeA = 0; + float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); + if (separationA > totalRadius) + return; + + int32 edgeB = 0; + float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); + if (separationB > totalRadius) + return; + + const b2PolygonShape* poly1; // reference polygon + const b2PolygonShape* poly2; // incident polygon + b2Transform xf1, xf2; + int32 edge1; // reference edge + uint8 flip; + const float32 k_relativeTol = 0.98f; + const float32 k_absoluteTol = 0.001f; + + if (separationB > k_relativeTol * separationA + k_absoluteTol) + { + poly1 = polyB; + poly2 = polyA; + xf1 = xfB; + xf2 = xfA; + edge1 = edgeB; + manifold->type = b2Manifold::e_faceB; + flip = 1; + } + else + { + poly1 = polyA; + poly2 = polyB; + xf1 = xfA; + xf2 = xfB; + edge1 = edgeA; + manifold->type = b2Manifold::e_faceA; + flip = 0; + } + + b2ClipVertex incidentEdge[2]; + b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + + int32 count1 = poly1->m_vertexCount; + const b2Vec2* vertices1 = poly1->m_vertices; + + int32 iv1 = edge1; + int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; + + b2Vec2 v11 = vertices1[iv1]; + b2Vec2 v12 = vertices1[iv2]; + + b2Vec2 localTangent = v12 - v11; + localTangent.Normalize(); + + b2Vec2 localNormal = b2Cross(localTangent, 1.0f); + b2Vec2 planePoint = 0.5f * (v11 + v12); + + b2Vec2 tangent = b2Mul(xf1.q, localTangent); + b2Vec2 normal = b2Cross(tangent, 1.0f); + + v11 = b2Mul(xf1, v11); + v12 = b2Mul(xf1, v12); + + // Face offset. + float32 frontOffset = b2Dot(normal, v11); + + // Side offsets, extended by polytope skin thickness. + float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; + float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; + + // Clip incident edge against extruded edge1 side edges. + b2ClipVertex clipPoints1[2]; + b2ClipVertex clipPoints2[2]; + int np; + + // Clip to box side 1 + np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); + + if (np < 2) + return; + + // Clip to negative box side 1 + np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); + + if (np < 2) + { + return; + } + + // Now clipPoints2 contains the clipped points. + manifold->localNormal = localNormal; + manifold->localPoint = planePoint; + + int32 pointCount = 0; + for (int32 i = 0; i < b2_maxManifoldPoints; ++i) + { + float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; + + if (separation <= totalRadius) + { + b2ManifoldPoint* cp = manifold->points + pointCount; + cp->localPoint = b2MulT(xf2, clipPoints2[i].v); + cp->id = clipPoints2[i].id; + if (flip) + { + // Swap features + b2ContactFeature cf = cp->id.cf; + cp->id.cf.indexA = cf.indexB; + cp->id.cf.indexB = cf.indexA; + cp->id.cf.typeA = cf.typeB; + cp->id.cf.typeB = cf.typeA; + } + ++pointCount; + } + } + + manifold->pointCount = pointCount; +} diff --git a/external/Box2D/Collision/b2Collision.cpp b/external/Box2D/Collision/b2Collision.cpp new file mode 100644 index 0000000000..2dd5ff0ab6 --- /dev/null +++ b/external/Box2D/Collision/b2Collision.cpp @@ -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 +#include + +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 = 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; +} diff --git a/external/Box2D/Collision/b2Collision.h b/external/Box2D/Collision/b2Collision.h new file mode 100644 index 0000000000..2e7386232b --- /dev/null +++ b/external/Box2D/Collision/b2Collision.h @@ -0,0 +1,276 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_COLLISION_H +#define B2_COLLISION_H + +#include +#include + +/// @file +/// Structures and functions used for computing contact points, distance +/// queries, and TOI queries. + +class b2Shape; +class b2CircleShape; +class b2EdgeShape; +class b2PolygonShape; + +const uint8 b2_nullFeature = UCHAR_MAX; + +/// The features that intersect to form the contact point +/// This must be 4 bytes or less. +struct b2ContactFeature +{ + enum Type + { + e_vertex = 0, + e_face = 1 + }; + + uint8 indexA; ///< Feature index on shapeA + uint8 indexB; ///< Feature index on shapeB + uint8 typeA; ///< The feature type on shapeA + uint8 typeB; ///< The feature type on shapeB +}; + +/// Contact ids to facilitate warm starting. +union b2ContactID +{ + b2ContactFeature cf; + uint32 key; ///< Used to quickly compare contact ids. +}; + +/// A manifold point is a contact point belonging to a contact +/// manifold. It holds details related to the geometry and dynamics +/// of the contact points. +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleB +/// -e_faceA: the local center of cirlceB or the clip point of polygonB +/// -e_faceB: the clip point of polygonA +/// This structure is stored across time steps, so we keep it small. +/// Note: the impulses are used for internal caching and may not +/// provide reliable contact forces, especially for high speed collisions. +struct b2ManifoldPoint +{ + b2Vec2 localPoint; ///< usage depends on manifold type + float32 normalImpulse; ///< the non-penetration impulse + float32 tangentImpulse; ///< the friction impulse + b2ContactID id; ///< uniquely identifies a contact point between two shapes +}; + +/// A manifold for two touching convex shapes. +/// Box2D supports multiple types of contact: +/// - clip point versus plane with radius +/// - point versus point with radius (circles) +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleA +/// -e_faceA: the center of faceA +/// -e_faceB: the center of faceB +/// Similarly the local normal usage: +/// -e_circles: not used +/// -e_faceA: the normal on polygonA +/// -e_faceB: the normal on polygonB +/// We store contacts in this way so that position correction can +/// account for movement, which is critical for continuous physics. +/// All contact scenarios must be expressed in one of these types. +/// This structure is stored across time steps, so we keep it small. +struct b2Manifold +{ + enum Type + { + e_circles, + e_faceA, + e_faceB + }; + + b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact + b2Vec2 localNormal; ///< not use for Type::e_points + b2Vec2 localPoint; ///< usage depends on manifold type + Type type; + int32 pointCount; ///< the number of manifold points +}; + +/// This is used to compute the current state of a contact manifold. +struct b2WorldManifold +{ + /// Evaluate the manifold with supplied transforms. This assumes + /// modest motion from the original state. This does not change the + /// point count, impulses, etc. The radii must come from the shapes + /// that generated the manifold. + void Initialize(const b2Manifold* manifold, + const b2Transform& xfA, float32 radiusA, + const b2Transform& xfB, float32 radiusB); + + b2Vec2 normal; ///< world vector pointing from A to B + b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) +}; + +/// This is used for determining the state of contact points. +enum b2PointState +{ + b2_nullState, ///< point does not exist + b2_addState, ///< point was added in the update + b2_persistState, ///< point persisted across the update + b2_removeState ///< point was removed in the update +}; + +/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 +/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. +void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], + const b2Manifold* manifold1, const b2Manifold* manifold2); + +/// Used for computing contact manifolds. +struct b2ClipVertex +{ + b2Vec2 v; + b2ContactID id; +}; + +/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). +struct b2RayCastInput +{ + b2Vec2 p1, p2; + float32 maxFraction; +}; + +/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 +/// come from b2RayCastInput. +struct b2RayCastOutput +{ + b2Vec2 normal; + float32 fraction; +}; + +/// An axis aligned bounding box. +struct b2AABB +{ + /// Verify that the bounds are sorted. + bool IsValid() const; + + /// Get the center of the AABB. + b2Vec2 GetCenter() const + { + return 0.5f * (lowerBound + upperBound); + } + + /// Get the extents of the AABB (half-widths). + b2Vec2 GetExtents() const + { + return 0.5f * (upperBound - lowerBound); + } + + /// Get the perimeter length + float32 GetPerimeter() const + { + float32 wx = upperBound.x - lowerBound.x; + float32 wy = upperBound.y - lowerBound.y; + return 2.0f * (wx + wy); + } + + /// Combine an AABB into this one. + void Combine(const b2AABB& aabb) + { + lowerBound = b2Min(lowerBound, aabb.lowerBound); + upperBound = b2Max(upperBound, aabb.upperBound); + } + + /// Combine two AABBs into this one. + void Combine(const b2AABB& aabb1, const b2AABB& aabb2) + { + lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); + upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); + } + + /// Does this aabb contain the provided AABB. + bool Contains(const b2AABB& aabb) const + { + bool result = true; + result = result && lowerBound.x <= aabb.lowerBound.x; + result = result && lowerBound.y <= aabb.lowerBound.y; + result = result && aabb.upperBound.x <= upperBound.x; + result = result && aabb.upperBound.y <= upperBound.y; + return result; + } + + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; + + b2Vec2 lowerBound; ///< the lower vertex + b2Vec2 upperBound; ///< the upper vertex +}; + +/// Compute the collision manifold between two circles. +void b2CollideCircles(b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between a polygon and a circle. +void b2CollidePolygonAndCircle(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between two polygons. +void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndCircle(b2Manifold* manifold, + const b2EdgeShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +void b2CollideEdgeAndPolygon(b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* circleB, const b2Transform& xfB); + +/// Clipping for contact manifolds. +int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], + const b2Vec2& normal, float32 offset, int32 vertexIndexA); + +/// Determine if two generic shapes overlap. +bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, + const b2Shape* shapeB, int32 indexB, + const b2Transform& xfA, const b2Transform& xfB); + +// ---------------- Inline Functions ------------------------------------------ + +inline bool b2AABB::IsValid() const +{ + b2Vec2 d = upperBound - lowerBound; + bool valid = d.x >= 0.0f && d.y >= 0.0f; + valid = valid && lowerBound.IsValid() && upperBound.IsValid(); + return valid; +} + +inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) +{ + b2Vec2 d1, d2; + d1 = b.lowerBound - a.upperBound; + d2 = a.lowerBound - b.upperBound; + + if (d1.x > 0.0f || d1.y > 0.0f) + return false; + + if (d2.x > 0.0f || d2.y > 0.0f) + return false; + + return true; +} + +#endif diff --git a/external/Box2D/Collision/b2Distance.cpp b/external/Box2D/Collision/b2Distance.cpp new file mode 100644 index 0000000000..ac67d3be43 --- /dev/null +++ b/external/Box2D/Collision/b2Distance.cpp @@ -0,0 +1,603 @@ +/* +* 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 +#include +#include +#include +#include + +// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. +int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; + +void b2DistanceProxy::Set(const b2Shape* shape, int32 index) +{ + switch (shape->GetType()) + { + case b2Shape::e_circle: + { + const b2CircleShape* circle = (b2CircleShape*)shape; + m_vertices = &circle->m_p; + m_count = 1; + m_radius = circle->m_radius; + } + break; + + case b2Shape::e_polygon: + { + const b2PolygonShape* polygon = (b2PolygonShape*)shape; + m_vertices = polygon->m_vertices; + m_count = polygon->m_vertexCount; + m_radius = polygon->m_radius; + } + break; + + case b2Shape::e_chain: + { + const b2ChainShape* chain = (b2ChainShape*)shape; + b2Assert(0 <= index && index < chain->m_count); + + m_buffer[0] = chain->m_vertices[index]; + if (index + 1 < chain->m_count) + { + m_buffer[1] = chain->m_vertices[index + 1]; + } + else + { + m_buffer[1] = chain->m_vertices[0]; + } + + m_vertices = m_buffer; + m_count = 2; + m_radius = chain->m_radius; + } + break; + + case b2Shape::e_edge: + { + const b2EdgeShape* edge = (b2EdgeShape*)shape; + m_vertices = &edge->m_vertex1; + m_count = 2; + m_radius = edge->m_radius; + } + break; + + default: + b2Assert(false); + } +} + + +struct b2SimplexVertex +{ + b2Vec2 wA; // support point in proxyA + b2Vec2 wB; // support point in proxyB + b2Vec2 w; // wB - wA + float32 a; // barycentric coordinate for closest point + int32 indexA; // wA index + int32 indexB; // wB index +}; + +struct b2Simplex +{ + void ReadCache( const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Transform& transformA, + const b2DistanceProxy* proxyB, const b2Transform& transformB) + { + b2Assert(cache->count <= 3); + + // Copy data from cache. + m_count = cache->count; + b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + b2SimplexVertex* v = vertices + i; + v->indexA = cache->indexA[i]; + v->indexB = cache->indexB[i]; + b2Vec2 wALocal = proxyA->GetVertex(v->indexA); + b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + v->a = 0.0f; + } + + // Compute the new simplex metric, if it is substantially different than + // old metric then flush the simplex. + if (m_count > 1) + { + float32 metric1 = cache->metric; + float32 metric2 = GetMetric(); + if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) + { + // Reset the simplex. + m_count = 0; + } + } + + // If the cache is empty or invalid ... + if (m_count == 0) + { + b2SimplexVertex* v = vertices + 0; + v->indexA = 0; + v->indexB = 0; + b2Vec2 wALocal = proxyA->GetVertex(0); + b2Vec2 wBLocal = proxyB->GetVertex(0); + v->wA = b2Mul(transformA, wALocal); + v->wB = b2Mul(transformB, wBLocal); + v->w = v->wB - v->wA; + m_count = 1; + } + } + + void WriteCache(b2SimplexCache* cache) const + { + cache->metric = GetMetric(); + cache->count = uint16(m_count); + const b2SimplexVertex* vertices = &m_v1; + for (int32 i = 0; i < m_count; ++i) + { + cache->indexA[i] = uint8(vertices[i].indexA); + cache->indexB[i] = uint8(vertices[i].indexB); + } + } + + b2Vec2 GetSearchDirection() const + { + switch (m_count) + { + case 1: + return -m_v1.w; + + case 2: + { + b2Vec2 e12 = m_v2.w - m_v1.w; + float32 sgn = b2Cross(e12, -m_v1.w); + if (sgn > 0.0f) + { + // Origin is left of e12. + return b2Cross(1.0f, e12); + } + else + { + // Origin is right of e12. + return b2Cross(e12, 1.0f); + } + } + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + b2Vec2 GetClosestPoint() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return b2Vec2_zero; + + case 1: + return m_v1.w; + + case 2: + return m_v1.a * m_v1.w + m_v2.a * m_v2.w; + + case 3: + return b2Vec2_zero; + + default: + b2Assert(false); + return b2Vec2_zero; + } + } + + void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const + { + switch (m_count) + { + case 0: + b2Assert(false); + break; + + case 1: + *pA = m_v1.wA; + *pB = m_v1.wB; + break; + + case 2: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; + *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; + break; + + case 3: + *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; + *pB = *pA; + break; + + default: + b2Assert(false); + break; + } + } + + float32 GetMetric() const + { + switch (m_count) + { + case 0: + b2Assert(false); + return 0.0; + + case 1: + return 0.0f; + + case 2: + return b2Distance(m_v1.w, m_v2.w); + + case 3: + return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); + + default: + b2Assert(false); + return 0.0f; + } + } + + void Solve2(); + void Solve3(); + + b2SimplexVertex m_v1, m_v2, m_v3; + int32 m_count; +}; + + +// Solve a line segment using barycentric coordinates. +// +// p = a1 * w1 + a2 * w2 +// a1 + a2 = 1 +// +// The vector from the origin to the closest point on the line is +// perpendicular to the line. +// e12 = w2 - w1 +// dot(p, e) = 0 +// a1 * dot(w1, e) + a2 * dot(w2, e) = 0 +// +// 2-by-2 linear system +// [1 1 ][a1] = [1] +// [w1.e12 w2.e12][a2] = [0] +// +// Define +// d12_1 = dot(w2, e12) +// d12_2 = -dot(w1, e12) +// d12 = d12_1 + d12_2 +// +// Solution +// a1 = d12_1 / d12 +// a2 = d12_2 / d12 +void b2Simplex::Solve2() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 e12 = w2 - w1; + + // w1 region + float32 d12_2 = -b2Dot(w1, e12); + if (d12_2 <= 0.0f) + { + // a2 <= 0, so we clamp it to 0 + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // w2 region + float32 d12_1 = b2Dot(w2, e12); + if (d12_1 <= 0.0f) + { + // a1 <= 0, so we clamp it to 0 + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // Must be in e12 region. + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; +} + +// Possible regions: +// - points[2] +// - edge points[0]-points[2] +// - edge points[1]-points[2] +// - inside the triangle +void b2Simplex::Solve3() +{ + b2Vec2 w1 = m_v1.w; + b2Vec2 w2 = m_v2.w; + b2Vec2 w3 = m_v3.w; + + // Edge12 + // [1 1 ][a1] = [1] + // [w1.e12 w2.e12][a2] = [0] + // a3 = 0 + b2Vec2 e12 = w2 - w1; + float32 w1e12 = b2Dot(w1, e12); + float32 w2e12 = b2Dot(w2, e12); + float32 d12_1 = w2e12; + float32 d12_2 = -w1e12; + + // Edge13 + // [1 1 ][a1] = [1] + // [w1.e13 w3.e13][a3] = [0] + // a2 = 0 + b2Vec2 e13 = w3 - w1; + float32 w1e13 = b2Dot(w1, e13); + float32 w3e13 = b2Dot(w3, e13); + float32 d13_1 = w3e13; + float32 d13_2 = -w1e13; + + // Edge23 + // [1 1 ][a2] = [1] + // [w2.e23 w3.e23][a3] = [0] + // a1 = 0 + b2Vec2 e23 = w3 - w2; + float32 w2e23 = b2Dot(w2, e23); + float32 w3e23 = b2Dot(w3, e23); + float32 d23_1 = w3e23; + float32 d23_2 = -w2e23; + + // Triangle123 + float32 n123 = b2Cross(e12, e13); + + float32 d123_1 = n123 * b2Cross(w2, w3); + float32 d123_2 = n123 * b2Cross(w3, w1); + float32 d123_3 = n123 * b2Cross(w1, w2); + + // w1 region + if (d12_2 <= 0.0f && d13_2 <= 0.0f) + { + m_v1.a = 1.0f; + m_count = 1; + return; + } + + // e12 + if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) + { + float32 inv_d12 = 1.0f / (d12_1 + d12_2); + m_v1.a = d12_1 * inv_d12; + m_v2.a = d12_2 * inv_d12; + m_count = 2; + return; + } + + // e13 + if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) + { + float32 inv_d13 = 1.0f / (d13_1 + d13_2); + m_v1.a = d13_1 * inv_d13; + m_v3.a = d13_2 * inv_d13; + m_count = 2; + m_v2 = m_v3; + return; + } + + // w2 region + if (d12_1 <= 0.0f && d23_2 <= 0.0f) + { + m_v2.a = 1.0f; + m_count = 1; + m_v1 = m_v2; + return; + } + + // w3 region + if (d13_1 <= 0.0f && d23_1 <= 0.0f) + { + m_v3.a = 1.0f; + m_count = 1; + m_v1 = m_v3; + return; + } + + // e23 + if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) + { + float32 inv_d23 = 1.0f / (d23_1 + d23_2); + m_v2.a = d23_1 * inv_d23; + m_v3.a = d23_2 * inv_d23; + m_count = 2; + m_v1 = m_v3; + return; + } + + // Must be in triangle123 + float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); + m_v1.a = d123_1 * inv_d123; + m_v2.a = d123_2 * inv_d123; + m_v3.a = d123_3 * inv_d123; + m_count = 3; +} + +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input) +{ + ++b2_gjkCalls; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Transform transformA = input->transformA; + b2Transform transformB = input->transformB; + + // Initialize the simplex. + b2Simplex simplex; + simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); + + // Get simplex vertices as an array. + b2SimplexVertex* vertices = &simplex.m_v1; + const int32 k_maxIters = 20; + + // These store the vertices of the last simplex so that we + // can check for duplicates and prevent cycling. + int32 saveA[3], saveB[3]; + int32 saveCount = 0; + + b2Vec2 closestPoint = simplex.GetClosestPoint(); + float32 distanceSqr1 = closestPoint.LengthSquared(); + float32 distanceSqr2 = distanceSqr1; + + // Main iteration loop. + int32 iter = 0; + while (iter < k_maxIters) + { + // Copy simplex so we can identify duplicates. + saveCount = simplex.m_count; + for (int32 i = 0; i < saveCount; ++i) + { + saveA[i] = vertices[i].indexA; + saveB[i] = vertices[i].indexB; + } + + switch (simplex.m_count) + { + case 1: + break; + + case 2: + simplex.Solve2(); + break; + + case 3: + simplex.Solve3(); + break; + + default: + b2Assert(false); + } + + // If we have 3 points, then the origin is in the corresponding triangle. + if (simplex.m_count == 3) + { + break; + } + + // Compute closest point. + b2Vec2 p = simplex.GetClosestPoint(); + distanceSqr2 = p.LengthSquared(); + + // Ensure progress + if (distanceSqr2 >= distanceSqr1) + { + //break; + } + distanceSqr1 = distanceSqr2; + + // Get search direction. + b2Vec2 d = simplex.GetSearchDirection(); + + // Ensure the search direction is numerically fit. + if (d.LengthSquared() < b2_epsilon * b2_epsilon) + { + // The origin is probably contained by a line segment + // or triangle. Thus the shapes are overlapped. + + // We can't return zero here even though there may be overlap. + // In case the simplex is a point, segment, or triangle it is difficult + // to determine if the origin is contained in the CSO or very close to it. + break; + } + + // Compute a tentative new simplex vertex using support points. + b2SimplexVertex* vertex = vertices + simplex.m_count; + vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); + vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); + b2Vec2 wBLocal; + vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); + vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); + vertex->w = vertex->wB - vertex->wA; + + // Iteration count is equated to the number of support point calls. + ++iter; + ++b2_gjkIters; + + // Check for duplicate support points. This is the main termination criteria. + bool duplicate = false; + for (int32 i = 0; i < saveCount; ++i) + { + if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) + { + duplicate = true; + break; + } + } + + // If we found a duplicate support point we must exit to avoid cycling. + if (duplicate) + { + break; + } + + // New vertex is ok and needed. + ++simplex.m_count; + } + + b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); + + // Prepare output. + simplex.GetWitnessPoints(&output->pointA, &output->pointB); + output->distance = b2Distance(output->pointA, output->pointB); + output->iterations = iter; + + // Cache the simplex. + simplex.WriteCache(cache); + + // Apply radii if requested. + if (input->useRadii) + { + float32 rA = proxyA->m_radius; + float32 rB = proxyB->m_radius; + + if (output->distance > rA + rB && output->distance > b2_epsilon) + { + // Shapes are still no overlapped. + // Move the witness points to the outer surface. + output->distance -= rA + rB; + b2Vec2 normal = output->pointB - output->pointA; + normal.Normalize(); + output->pointA += rA * normal; + output->pointB -= rB * normal; + } + else + { + // Shapes are overlapped when radii are considered. + // Move the witness points to the middle. + b2Vec2 p = 0.5f * (output->pointA + output->pointB); + output->pointA = p; + output->pointB = p; + output->distance = 0.0f; + } + } +} diff --git a/external/Box2D/Collision/b2Distance.h b/external/Box2D/Collision/b2Distance.h new file mode 100644 index 0000000000..d598b7339d --- /dev/null +++ b/external/Box2D/Collision/b2Distance.h @@ -0,0 +1,141 @@ + +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_DISTANCE_H +#define B2_DISTANCE_H + +#include + +class b2Shape; + +/// A distance proxy is used by the GJK algorithm. +/// It encapsulates any shape. +struct b2DistanceProxy +{ + b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} + + /// Initialize the proxy using the given shape. The shape + /// must remain in scope while the proxy is in use. + void Set(const b2Shape* shape, int32 index); + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const; + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_buffer[2]; + const b2Vec2* m_vertices; + int32 m_count; + float32 m_radius; +}; + +/// Used to warm start b2Distance. +/// Set count to zero on first call. +struct b2SimplexCache +{ + float32 metric; ///< length or area + uint16 count; + uint8 indexA[3]; ///< vertices on shape A + uint8 indexB[3]; ///< vertices on shape B +}; + +/// Input for b2Distance. +/// You have to option to use the shape radii +/// in the computation. Even +struct b2DistanceInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Transform transformA; + b2Transform transformB; + bool useRadii; +}; + +/// Output for b2Distance. +struct b2DistanceOutput +{ + b2Vec2 pointA; ///< closest point on shapeA + b2Vec2 pointB; ///< closest point on shapeB + float32 distance; + int32 iterations; ///< number of GJK iterations used +}; + +/// Compute the closest points between two shapes. Supports any combination of: +/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. +/// On the first call set b2SimplexCache.count to zero. +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input); + + +////////////////////////////////////////////////////////////////////////// + +inline int32 b2DistanceProxy::GetVertexCount() const +{ + return m_count; +} + +inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_count); + return m_vertices[index]; +} + +inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return bestIndex; +} + +inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return m_vertices[bestIndex]; +} + +#endif diff --git a/external/Box2D/Collision/b2DynamicTree.cpp b/external/Box2D/Collision/b2DynamicTree.cpp new file mode 100644 index 0000000000..d1d53297e2 --- /dev/null +++ b/external/Box2D/Collision/b2DynamicTree.cpp @@ -0,0 +1,775 @@ +/* +* Copyright (c) 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 +#include +#ifndef SHP +#include +#else +#include +#endif +using namespace std; + + +b2DynamicTree::b2DynamicTree() +{ + m_root = b2_nullNode; + + m_nodeCapacity = 16; + m_nodeCount = 0; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); + + // Build a linked list for the free list. + for (int32 i = 0; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = 0; + + m_path = 0; + + m_insertionCount = 0; +} + +b2DynamicTree::~b2DynamicTree() +{ + // This frees the entire tree in one shot. + b2Free(m_nodes); +} + +// Allocate a node from the pool. Grow the pool if necessary. +int32 b2DynamicTree::AllocateNode() +{ + // Expand the node pool as needed. + if (m_freeList == b2_nullNode) + { + b2Assert(m_nodeCount == m_nodeCapacity); + + // The free list is empty. Rebuild a bigger pool. + b2TreeNode* oldNodes = m_nodes; + m_nodeCapacity *= 2; + m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); + memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); + b2Free(oldNodes); + + // Build a linked list for the free list. The parent + // pointer becomes the "next" pointer. + for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) + { + m_nodes[i].next = i + 1; + m_nodes[i].height = -1; + } + m_nodes[m_nodeCapacity-1].next = b2_nullNode; + m_nodes[m_nodeCapacity-1].height = -1; + m_freeList = m_nodeCount; + } + + // Peel a node off the free list. + int32 nodeId = m_freeList; + m_freeList = m_nodes[nodeId].next; + m_nodes[nodeId].parent = b2_nullNode; + m_nodes[nodeId].child1 = b2_nullNode; + m_nodes[nodeId].child2 = b2_nullNode; + m_nodes[nodeId].height = 0; + m_nodes[nodeId].userData = NULL; + ++m_nodeCount; + return nodeId; +} + +// Return a node to the pool. +void b2DynamicTree::FreeNode(int32 nodeId) +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2Assert(0 < m_nodeCount); + m_nodes[nodeId].next = m_freeList; + m_nodes[nodeId].height = -1; + m_freeList = nodeId; + --m_nodeCount; +} + +// Create a proxy in the tree as a leaf node. We return the index +// of the node instead of a pointer so that we can grow +// the node pool. +int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) +{ + int32 proxyId = AllocateNode(); + + // Fatten the aabb. + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; + m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; + m_nodes[proxyId].userData = userData; + m_nodes[proxyId].height = 0; + + InsertLeaf(proxyId); + + return proxyId; +} + +void b2DynamicTree::DestroyProxy(int32 proxyId) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + b2Assert(m_nodes[proxyId].IsLeaf()); + + RemoveLeaf(proxyId); + FreeNode(proxyId); +} + +bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + + b2Assert(m_nodes[proxyId].IsLeaf()); + + if (m_nodes[proxyId].aabb.Contains(aabb)) + { + return false; + } + + RemoveLeaf(proxyId); + + // Extend AABB. + b2AABB b = aabb; + b2Vec2 r(b2_aabbExtension, b2_aabbExtension); + b.lowerBound = b.lowerBound - r; + b.upperBound = b.upperBound + r; + + // Predict AABB displacement. + b2Vec2 d = b2_aabbMultiplier * displacement; + + if (d.x < 0.0f) + { + b.lowerBound.x += d.x; + } + else + { + b.upperBound.x += d.x; + } + + if (d.y < 0.0f) + { + b.lowerBound.y += d.y; + } + else + { + b.upperBound.y += d.y; + } + + m_nodes[proxyId].aabb = b; + + InsertLeaf(proxyId); + return true; +} + +void b2DynamicTree::InsertLeaf(int32 leaf) +{ + ++m_insertionCount; + + if (m_root == b2_nullNode) + { + m_root = leaf; + m_nodes[m_root].parent = b2_nullNode; + return; + } + + // Find the best sibling for this node + b2AABB leafAABB = m_nodes[leaf].aabb; + int32 index = m_root; + while (m_nodes[index].IsLeaf() == false) + { + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + float32 area = m_nodes[index].aabb.GetPerimeter(); + + b2AABB combinedAABB; + combinedAABB.Combine(m_nodes[index].aabb, leafAABB); + float32 combinedArea = combinedAABB.GetPerimeter(); + + // Cost of creating a new parent for this node and the new leaf + float32 cost = 2.0f * combinedArea; + + // Minimum cost of pushing the leaf further down the tree + float32 inheritanceCost = 2.0f * (combinedArea - area); + + // Cost of descending into child1 + float32 cost1; + if (m_nodes[child1].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + cost1 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child1].aabb); + float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost1 = (newArea - oldArea) + inheritanceCost; + } + + // Cost of descending into child2 + float32 cost2; + if (m_nodes[child2].IsLeaf()) + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + cost2 = aabb.GetPerimeter() + inheritanceCost; + } + else + { + b2AABB aabb; + aabb.Combine(leafAABB, m_nodes[child2].aabb); + float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); + float32 newArea = aabb.GetPerimeter(); + cost2 = newArea - oldArea + inheritanceCost; + } + + // Descend according to the minimum cost. + if (cost < cost1 && cost < cost2) + { + break; + } + + // Descend + if (cost1 < cost2) + { + index = child1; + } + else + { + index = child2; + } + } + + int32 sibling = index; + + // Create a new parent. + int32 oldParent = m_nodes[sibling].parent; + int32 newParent = AllocateNode(); + m_nodes[newParent].parent = oldParent; + m_nodes[newParent].userData = NULL; + m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); + m_nodes[newParent].height = m_nodes[sibling].height + 1; + + if (oldParent != b2_nullNode) + { + // The sibling was not the root. + if (m_nodes[oldParent].child1 == sibling) + { + m_nodes[oldParent].child1 = newParent; + } + else + { + m_nodes[oldParent].child2 = newParent; + } + + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + } + else + { + // The sibling was the root. + m_nodes[newParent].child1 = sibling; + m_nodes[newParent].child2 = leaf; + m_nodes[sibling].parent = newParent; + m_nodes[leaf].parent = newParent; + m_root = newParent; + } + + // Walk back up the tree fixing heights and AABBs + index = m_nodes[leaf].parent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + b2Assert(child1 != b2_nullNode); + b2Assert(child2 != b2_nullNode); + + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + index = m_nodes[index].parent; + } + + //Validate(); +} + +void b2DynamicTree::RemoveLeaf(int32 leaf) +{ + if (leaf == m_root) + { + m_root = b2_nullNode; + return; + } + + int32 parent = m_nodes[leaf].parent; + int32 grandParent = m_nodes[parent].parent; + int32 sibling; + if (m_nodes[parent].child1 == leaf) + { + sibling = m_nodes[parent].child2; + } + else + { + sibling = m_nodes[parent].child1; + } + + if (grandParent != b2_nullNode) + { + // Destroy parent and connect sibling to grandParent. + if (m_nodes[grandParent].child1 == parent) + { + m_nodes[grandParent].child1 = sibling; + } + else + { + m_nodes[grandParent].child2 = sibling; + } + m_nodes[sibling].parent = grandParent; + FreeNode(parent); + + // Adjust ancestor bounds. + int32 index = grandParent; + while (index != b2_nullNode) + { + index = Balance(index); + + int32 child1 = m_nodes[index].child1; + int32 child2 = m_nodes[index].child2; + + m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); + + index = m_nodes[index].parent; + } + } + else + { + m_root = sibling; + m_nodes[sibling].parent = b2_nullNode; + FreeNode(parent); + } + + //Validate(); +} + +// Perform a left or right rotation if node A is imbalanced. +// Returns the new root index. +int32 b2DynamicTree::Balance(int32 iA) +{ + b2Assert(iA != b2_nullNode); + + b2TreeNode* A = m_nodes + iA; + if (A->IsLeaf() || A->height < 2) + { + return iA; + } + + int32 iB = A->child1; + int32 iC = A->child2; + b2Assert(0 <= iB && iB < m_nodeCapacity); + b2Assert(0 <= iC && iC < m_nodeCapacity); + + b2TreeNode* B = m_nodes + iB; + b2TreeNode* C = m_nodes + iC; + + int32 balance = C->height - B->height; + + // Rotate C up + if (balance > 1) + { + int32 iF = C->child1; + int32 iG = C->child2; + b2TreeNode* F = m_nodes + iF; + b2TreeNode* G = m_nodes + iG; + b2Assert(0 <= iF && iF < m_nodeCapacity); + b2Assert(0 <= iG && iG < m_nodeCapacity); + + // Swap A and C + C->child1 = iA; + C->parent = A->parent; + A->parent = iC; + + // A's old parent should point to C + if (C->parent != b2_nullNode) + { + if (m_nodes[C->parent].child1 == iA) + { + m_nodes[C->parent].child1 = iC; + } + else + { + b2Assert(m_nodes[C->parent].child2 == iA); + m_nodes[C->parent].child2 = iC; + } + } + else + { + m_root = iC; + } + + // Rotate + if (F->height > G->height) + { + C->child2 = iF; + A->child2 = iG; + G->parent = iA; + A->aabb.Combine(B->aabb, G->aabb); + C->aabb.Combine(A->aabb, F->aabb); + + A->height = 1 + b2Max(B->height, G->height); + C->height = 1 + b2Max(A->height, F->height); + } + else + { + C->child2 = iG; + A->child2 = iF; + F->parent = iA; + A->aabb.Combine(B->aabb, F->aabb); + C->aabb.Combine(A->aabb, G->aabb); + + A->height = 1 + b2Max(B->height, F->height); + C->height = 1 + b2Max(A->height, G->height); + } + + return iC; + } + + // Rotate B up + if (balance < -1) + { + int32 iD = B->child1; + int32 iE = B->child2; + b2TreeNode* D = m_nodes + iD; + b2TreeNode* E = m_nodes + iE; + b2Assert(0 <= iD && iD < m_nodeCapacity); + b2Assert(0 <= iE && iE < m_nodeCapacity); + + // Swap A and B + B->child1 = iA; + B->parent = A->parent; + A->parent = iB; + + // A's old parent should point to B + if (B->parent != b2_nullNode) + { + if (m_nodes[B->parent].child1 == iA) + { + m_nodes[B->parent].child1 = iB; + } + else + { + b2Assert(m_nodes[B->parent].child2 == iA); + m_nodes[B->parent].child2 = iB; + } + } + else + { + m_root = iB; + } + + // Rotate + if (D->height > E->height) + { + B->child2 = iD; + A->child1 = iE; + E->parent = iA; + A->aabb.Combine(C->aabb, E->aabb); + B->aabb.Combine(A->aabb, D->aabb); + + A->height = 1 + b2Max(C->height, E->height); + B->height = 1 + b2Max(A->height, D->height); + } + else + { + B->child2 = iE; + A->child1 = iD; + D->parent = iA; + A->aabb.Combine(C->aabb, D->aabb); + B->aabb.Combine(A->aabb, E->aabb); + + A->height = 1 + b2Max(C->height, D->height); + B->height = 1 + b2Max(A->height, E->height); + } + + return iB; + } + + return iA; +} + +int32 b2DynamicTree::GetHeight() const +{ + if (m_root == b2_nullNode) + { + return 0; + } + + return m_nodes[m_root].height; +} + +// +float32 b2DynamicTree::GetAreaRatio() const +{ + if (m_root == b2_nullNode) + { + return 0.0f; + } + + const b2TreeNode* root = m_nodes + m_root; + float32 rootArea = root->aabb.GetPerimeter(); + + float32 totalArea = 0.0f; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height < 0) + { + // Free node in pool + continue; + } + + totalArea += node->aabb.GetPerimeter(); + } + + return totalArea / rootArea; +} + +// Compute the height of a sub-tree. +int32 b2DynamicTree::ComputeHeight(int32 nodeId) const +{ + b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); + b2TreeNode* node = m_nodes + nodeId; + + if (node->IsLeaf()) + { + return 0; + } + + int32 height1 = ComputeHeight(node->child1); + int32 height2 = ComputeHeight(node->child2); + return 1 + b2Max(height1, height2); +} + +int32 b2DynamicTree::ComputeHeight() const +{ + int32 height = ComputeHeight(m_root); + return height; +} + +void b2DynamicTree::ValidateStructure(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + if (index == m_root) + { + b2Assert(m_nodes[index].parent == b2_nullNode); + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + b2Assert(m_nodes[child1].parent == index); + b2Assert(m_nodes[child2].parent == index); + + ValidateStructure(child1); + ValidateStructure(child2); +} + +void b2DynamicTree::ValidateMetrics(int32 index) const +{ + if (index == b2_nullNode) + { + return; + } + + const b2TreeNode* node = m_nodes + index; + + int32 child1 = node->child1; + int32 child2 = node->child2; + + if (node->IsLeaf()) + { + b2Assert(child1 == b2_nullNode); + b2Assert(child2 == b2_nullNode); + b2Assert(node->height == 0); + return; + } + + b2Assert(0 <= child1 && child1 < m_nodeCapacity); + b2Assert(0 <= child2 && child2 < m_nodeCapacity); + + int32 height1 = m_nodes[child1].height; + int32 height2 = m_nodes[child2].height; + int32 height; + height = 1 + b2Max(height1, height2); + b2Assert(node->height == height); + + b2AABB aabb; + aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); + + b2Assert(aabb.lowerBound == node->aabb.lowerBound); + b2Assert(aabb.upperBound == node->aabb.upperBound); + + ValidateMetrics(child1); + ValidateMetrics(child2); +} + +void b2DynamicTree::Validate() const +{ + ValidateStructure(m_root); + ValidateMetrics(m_root); + + int32 freeCount = 0; + int32 freeIndex = m_freeList; + while (freeIndex != b2_nullNode) + { + b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); + freeIndex = m_nodes[freeIndex].next; + ++freeCount; + } + + b2Assert(GetHeight() == ComputeHeight()); + + b2Assert(m_nodeCount + freeCount == m_nodeCapacity); +} + +int32 b2DynamicTree::GetMaxBalance() const +{ + int32 maxBalance = 0; + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + const b2TreeNode* node = m_nodes + i; + if (node->height <= 1) + { + continue; + } + + b2Assert(node->IsLeaf() == false); + + int32 child1 = node->child1; + int32 child2 = node->child2; + int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); + maxBalance = b2Max(maxBalance, balance); + } + + return maxBalance; +} + +void b2DynamicTree::RebuildBottomUp() +{ + int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); + int32 count = 0; + + // Build array of leaves. Free the rest. + for (int32 i = 0; i < m_nodeCapacity; ++i) + { + if (m_nodes[i].height < 0) + { + // free node in pool + continue; + } + + if (m_nodes[i].IsLeaf()) + { + m_nodes[i].parent = b2_nullNode; + nodes[count] = i; + ++count; + } + else + { + FreeNode(i); + } + } + + while (count > 1) + { + float32 minCost = b2_maxFloat; + int32 iMin = -1, jMin = -1; + for (int32 i = 0; i < count; ++i) + { + b2AABB aabbi = m_nodes[nodes[i]].aabb; + + for (int32 j = i + 1; j < count; ++j) + { + b2AABB aabbj = m_nodes[nodes[j]].aabb; + b2AABB b; + b.Combine(aabbi, aabbj); + float32 cost = b.GetPerimeter(); + if (cost < minCost) + { + iMin = i; + jMin = j; + minCost = cost; + } + } + } + + int32 index1 = nodes[iMin]; + int32 index2 = nodes[jMin]; + b2TreeNode* child1 = m_nodes + index1; + b2TreeNode* child2 = m_nodes + index2; + + int32 parentIndex = AllocateNode(); + b2TreeNode* parent = m_nodes + parentIndex; + parent->child1 = index1; + parent->child2 = index2; + parent->height = 1 + b2Max(child1->height, child2->height); + parent->aabb.Combine(child1->aabb, child2->aabb); + parent->parent = b2_nullNode; + + child1->parent = parentIndex; + child2->parent = parentIndex; + + nodes[jMin] = nodes[count-1]; + nodes[iMin] = parentIndex; + --count; + } + + m_root = nodes[0]; + b2Free(nodes); + + Validate(); +} diff --git a/external/Box2D/Collision/b2DynamicTree.h b/external/Box2D/Collision/b2DynamicTree.h new file mode 100644 index 0000000000..33f16b0f32 --- /dev/null +++ b/external/Box2D/Collision/b2DynamicTree.h @@ -0,0 +1,284 @@ +/* +* Copyright (c) 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. +*/ + +#ifndef B2_DYNAMIC_TREE_H +#define B2_DYNAMIC_TREE_H + +#include +#include + +#define b2_nullNode (-1) + +/// A node in the dynamic tree. The client does not interact with this directly. +struct b2TreeNode +{ + bool IsLeaf() const + { + return child1 == b2_nullNode; + } + + /// Enlarged AABB + b2AABB aabb; + + void* userData; + + union + { + int32 parent; + int32 next; + }; + + int32 child1; + int32 child2; + + // leaf = 0, free node = -1 + int32 height; +}; + +/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. +/// A dynamic tree arranges data in a binary tree to accelerate +/// queries such as volume queries and ray casts. Leafs are proxies +/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor +/// so that the proxy AABB is bigger than the client object. This allows the client +/// object to move by small amounts without triggering a tree update. +/// +/// Nodes are pooled and relocatable, so we use node indices rather than pointers. +class b2DynamicTree +{ +public: + /// Constructing the tree initializes the node pool. + b2DynamicTree(); + + /// Destroy the tree, freeing the node pool. + ~b2DynamicTree(); + + /// Create a proxy. Provide a tight fitting AABB and a userData pointer. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. This asserts if the id is invalid. + void DestroyProxy(int32 proxyId); + + /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, + /// then the proxy is removed from the tree and re-inserted. Otherwise + /// the function returns immediately. + /// @return true if the proxy was re-inserted. + bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); + + /// Get proxy user data. + /// @return the proxy user data or 0 if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Validate this tree. For testing. + void Validate() const; + + /// Compute the height of the binary tree in O(N) time. Should not be + /// called often. + int32 GetHeight() const; + + /// Get the maximum balance of an node in the tree. The balance is the difference + /// in height of the two children of a node. + int32 GetMaxBalance() const; + + /// Get the ratio of the sum of the node areas to the root area. + float32 GetAreaRatio() const; + + /// Build an optimal tree. Very expensive. For testing. + void RebuildBottomUp(); + +private: + + int32 AllocateNode(); + void FreeNode(int32 node); + + void InsertLeaf(int32 node); + void RemoveLeaf(int32 node); + + int32 Balance(int32 index); + + int32 ComputeHeight() const; + int32 ComputeHeight(int32 nodeId) const; + + void ValidateStructure(int32 index) const; + void ValidateMetrics(int32 index) const; + + int32 m_root; + + b2TreeNode* m_nodes; + int32 m_nodeCount; + int32 m_nodeCapacity; + + int32 m_freeList; + + /// This is used to incrementally traverse the tree for re-balancing. + uint32 m_path; + + int32 m_insertionCount; +}; + +inline void* b2DynamicTree::GetUserData(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].userData; +} + +inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].aabb; +} + +template +inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const +{ + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, aabb)) + { + if (node->IsLeaf()) + { + bool proceed = callback->QueryCallback(nodeId); + if (proceed == false) + { + return; + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } + } +} + +template +inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const +{ + b2Vec2 p1 = input.p1; + b2Vec2 p2 = input.p2; + b2Vec2 r = p2 - p1; + b2Assert(r.LengthSquared() > 0.0f); + r.Normalize(); + + // v is perpendicular to the segment. + b2Vec2 v = b2Cross(1.0f, r); + b2Vec2 abs_v = b2Abs(v); + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + + float32 maxFraction = input.maxFraction; + + // Build a bounding box for the segment. + b2AABB segmentAABB; + { + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, segmentAABB) == false) + { + continue; + } + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + b2Vec2 c = node->aabb.GetCenter(); + b2Vec2 h = node->aabb.GetExtents(); + float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); + if (separation > 0.0f) + { + continue; + } + + if (node->IsLeaf()) + { + b2RayCastInput subInput; + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = maxFraction; + + float32 value = callback->RayCastCallback(subInput, nodeId); + + if (value == 0.0f) + { + // The client has terminated the ray cast. + return; + } + + if (value > 0.0f) + { + // Update segment bounding box. + maxFraction = value; + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } +} + +#endif diff --git a/external/Box2D/Collision/b2TimeOfImpact.cpp b/external/Box2D/Collision/b2TimeOfImpact.cpp new file mode 100644 index 0000000000..1d643addd8 --- /dev/null +++ b/external/Box2D/Collision/b2TimeOfImpact.cpp @@ -0,0 +1,488 @@ +/* +* 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 +#include +#include +#include +#include + +#ifdef SHP +#include +#else +#include +#endif + +using namespace std; + +int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; +int32 b2_toiRootIters, b2_toiMaxRootIters; + +struct b2SeparationFunction +{ + enum Type + { + e_points, + e_faceA, + e_faceB + }; + + // TODO_ERIN might not need to return the separation + + float32 Initialize(const b2SimplexCache* cache, + const b2DistanceProxy* proxyA, const b2Sweep& sweepA, + const b2DistanceProxy* proxyB, const b2Sweep& sweepB, + float32 t1) + { + m_proxyA = proxyA; + m_proxyB = proxyB; + int32 count = cache->count; + b2Assert(0 < count && count < 3); + + m_sweepA = sweepA; + m_sweepB = sweepB; + + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t1); + m_sweepB.GetTransform(&xfB, t1); + + if (count == 1) + { + m_type = e_points; + b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + m_axis = pointB - pointA; + float32 s = m_axis.Normalize(); + return s; + } + else if (cache->indexA[0] == cache->indexA[1]) + { + // Two points on B and one on A. + m_type = e_faceB; + b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); + b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); + + m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfB.q, m_axis); + + m_localPoint = 0.5f * (localPointB1 + localPointB2); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 s = b2Dot(pointA - pointB, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + else + { + // Two points on A and one or two points on B. + m_type = e_faceA; + b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); + b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); + + m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); + m_axis.Normalize(); + b2Vec2 normal = b2Mul(xfA.q, m_axis); + + m_localPoint = 0.5f * (localPointA1 + localPointA2); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 s = b2Dot(pointB - pointA, normal); + if (s < 0.0f) + { + m_axis = -m_axis; + s = -s; + } + return s; + } + } + + float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + *indexA = m_proxyA->GetSupport(axisA); + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, m_axis); + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + *indexA = -1; + *indexB = m_proxyB->GetSupport(axisB); + + b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + *indexB = -1; + *indexA = m_proxyA->GetSupport(axisA); + + b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + *indexA = -1; + *indexB = -1; + return 0.0f; + } + } + + float32 Evaluate(int32 indexA, int32 indexB, float32 t) const + { + b2Transform xfA, xfB; + m_sweepA.GetTransform(&xfA, t); + m_sweepB.GetTransform(&xfB, t); + + switch (m_type) + { + case e_points: + { + b2Vec2 axisA = b2MulT(xfA.q, m_axis); + b2Vec2 axisB = b2MulT(xfB.q, -m_axis); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + + b2Vec2 pointA = b2Mul(xfA, localPointA); + b2Vec2 pointB = b2Mul(xfB, localPointB); + float32 separation = b2Dot(pointB - pointA, m_axis); + + return separation; + } + + case e_faceA: + { + b2Vec2 normal = b2Mul(xfA.q, m_axis); + b2Vec2 pointA = b2Mul(xfA, m_localPoint); + + b2Vec2 axisB = b2MulT(xfB.q, -normal); + + b2Vec2 localPointB = m_proxyB->GetVertex(indexB); + b2Vec2 pointB = b2Mul(xfB, localPointB); + + float32 separation = b2Dot(pointB - pointA, normal); + return separation; + } + + case e_faceB: + { + b2Vec2 normal = b2Mul(xfB.q, m_axis); + b2Vec2 pointB = b2Mul(xfB, m_localPoint); + + b2Vec2 axisA = b2MulT(xfA.q, -normal); + + b2Vec2 localPointA = m_proxyA->GetVertex(indexA); + b2Vec2 pointA = b2Mul(xfA, localPointA); + + float32 separation = b2Dot(pointA - pointB, normal); + return separation; + } + + default: + b2Assert(false); + return 0.0f; + } + } + + const b2DistanceProxy* m_proxyA; + const b2DistanceProxy* m_proxyB; + b2Sweep m_sweepA, m_sweepB; + Type m_type; + b2Vec2 m_localPoint; + b2Vec2 m_axis; +}; + +// CCD via the local separating axis method. This seeks progression +// by computing the largest time at which separation is maintained. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) +{ + ++b2_toiCalls; + + output->state = b2TOIOutput::e_unknown; + output->t = input->tMax; + + const b2DistanceProxy* proxyA = &input->proxyA; + const b2DistanceProxy* proxyB = &input->proxyB; + + b2Sweep sweepA = input->sweepA; + b2Sweep sweepB = input->sweepB; + + // Large rotations can make the root finder fail, so we normalize the + // sweep angles. + sweepA.Normalize(); + sweepB.Normalize(); + + float32 tMax = input->tMax; + + float32 totalRadius = proxyA->m_radius + proxyB->m_radius; + float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); + float32 tolerance = 0.25f * b2_linearSlop; + b2Assert(target > tolerance); + + float32 t1 = 0.0f; + const int32 k_maxIterations = 20; // TODO_ERIN b2Settings + int32 iter = 0; + + // Prepare input for distance query. + b2SimplexCache cache; + cache.count = 0; + b2DistanceInput distanceInput; + distanceInput.proxyA = input->proxyA; + distanceInput.proxyB = input->proxyB; + distanceInput.useRadii = false; + + // The outer loop progressively attempts to compute new separating axes. + // This loop terminates when an axis is repeated (no progress is made). + for(;;) + { + b2Transform xfA, xfB; + sweepA.GetTransform(&xfA, t1); + sweepB.GetTransform(&xfB, t1); + + // Get the distance between shapes. We can also use the results + // to get a separating axis. + distanceInput.transformA = xfA; + distanceInput.transformB = xfB; + b2DistanceOutput distanceOutput; + b2Distance(&distanceOutput, &cache, &distanceInput); + + // If the shapes are overlapped, we give up on continuous collision. + if (distanceOutput.distance <= 0.0f) + { + // Failure! + output->state = b2TOIOutput::e_overlapped; + output->t = 0.0f; + break; + } + + if (distanceOutput.distance < target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_touching; + output->t = t1; + break; + } + + // Initialize the separating axis. + b2SeparationFunction fcn; + fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); +#if 0 + // Dump the curve seen by the root finder + { + const int32 N = 100; + float32 dx = 1.0f / N; + float32 xs[N+1]; + float32 fs[N+1]; + + float32 x = 0.0f; + + for (int32 i = 0; i <= N; ++i) + { + sweepA.GetTransform(&xfA, x); + sweepB.GetTransform(&xfB, x); + float32 f = fcn.Evaluate(xfA, xfB) - target; + + printf("%g %g\n", x, f); + + xs[i] = x; + fs[i] = f; + + x += dx; + } + } +#endif + + // Compute the TOI on the separating axis. We do this by successively + // resolving the deepest point. This loop is bounded by the number of vertices. + bool done = false; + float32 t2 = tMax; + int32 pushBackIter = 0; + for (;;) + { + // Find the deepest point at t2. Store the witness point indices. + int32 indexA, indexB; + float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); + + // Is the final configuration separated? + if (s2 > target + tolerance) + { + // Victory! + output->state = b2TOIOutput::e_separated; + output->t = tMax; + done = true; + break; + } + + // Has the separation reached tolerance? + if (s2 > target - tolerance) + { + // Advance the sweeps + t1 = t2; + break; + } + + // Compute the initial separation of the witness points. + float32 s1 = fcn.Evaluate(indexA, indexB, t1); + + // Check for initial overlap. This might happen if the root finder + // runs out of iterations. + if (s1 < target - tolerance) + { + output->state = b2TOIOutput::e_failed; + output->t = t1; + done = true; + break; + } + + // Check for touching + if (s1 <= target + tolerance) + { + // Victory! t1 should hold the TOI (could be 0.0). + output->state = b2TOIOutput::e_touching; + output->t = t1; + done = true; + break; + } + + // Compute 1D root of: f(x) - target = 0 + int32 rootIterCount = 0; + float32 a1 = t1, a2 = t2; + for (;;) + { + // Use a mix of the secant rule and bisection. + float32 t; + if (rootIterCount & 1) + { + // Secant rule to improve convergence. + t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); + } + else + { + // Bisection to guarantee progress. + t = 0.5f * (a1 + a2); + } + + float32 s = fcn.Evaluate(indexA, indexB, t); + + if (b2Abs(s - target) < tolerance) + { + // t2 holds a tentative value for t1 + t2 = t; + break; + } + + // Ensure we continue to bracket the root. + if (s > target) + { + a1 = t; + s1 = s; + } + else + { + a2 = t; + s2 = s; + } + + ++rootIterCount; + ++b2_toiRootIters; + + if (rootIterCount == 50) + { + break; + } + } + + b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); + + ++pushBackIter; + + if (pushBackIter == b2_maxPolygonVertices) + { + break; + } + } + + ++iter; + ++b2_toiIters; + + if (done) + { + break; + } + + if (iter == k_maxIterations) + { + // Root finder got stuck. Semi-victory. + output->state = b2TOIOutput::e_failed; + output->t = t1; + break; + } + } + + b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); +} diff --git a/external/Box2D/Collision/b2TimeOfImpact.h b/external/Box2D/Collision/b2TimeOfImpact.h new file mode 100644 index 0000000000..2e4f8228ff --- /dev/null +++ b/external/Box2D/Collision/b2TimeOfImpact.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_TIME_OF_IMPACT_H +#define B2_TIME_OF_IMPACT_H + +#include +#include + +/// Input parameters for b2TimeOfImpact +struct b2TOIInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Sweep sweepA; + b2Sweep sweepB; + float32 tMax; // defines sweep interval [0, tMax] +}; + +// Output parameters for b2TimeOfImpact. +struct b2TOIOutput +{ + enum State + { + e_unknown, + e_failed, + e_overlapped, + e_touching, + e_separated + }; + + State state; + float32 t; +}; + +/// Compute the upper bound on time before two shapes penetrate. Time is represented as +/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, +/// non-tunneling collision. If you change the time interval, you should call this function +/// again. +/// Note: use b2Distance to compute the contact point and normal at the time of impact. +void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); + +#endif diff --git a/external/Box2D/Common/b2BlockAllocator.cpp b/external/Box2D/Common/b2BlockAllocator.cpp new file mode 100644 index 0000000000..2e862091f9 --- /dev/null +++ b/external/Box2D/Common/b2BlockAllocator.cpp @@ -0,0 +1,218 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include + +using namespace std; + +int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = +{ + 16, // 0 + 32, // 1 + 64, // 2 + 96, // 3 + 128, // 4 + 160, // 5 + 192, // 6 + 224, // 7 + 256, // 8 + 320, // 9 + 384, // 10 + 448, // 11 + 512, // 12 + 640, // 13 +}; +uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; +bool b2BlockAllocator::s_blockSizeLookupInitialized; + +struct b2Chunk +{ + int32 blockSize; + b2Block* blocks; +}; + +struct b2Block +{ + b2Block* next; +}; + +b2BlockAllocator::b2BlockAllocator() +{ + b2Assert(b2_blockSizes < UCHAR_MAX); + + m_chunkSpace = b2_chunkArrayIncrement; + m_chunkCount = 0; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + memset(m_freeLists, 0, sizeof(m_freeLists)); + + if (s_blockSizeLookupInitialized == false) + { + int32 j = 0; + for (int32 i = 1; i <= b2_maxBlockSize; ++i) + { + b2Assert(j < b2_blockSizes); + if (i <= s_blockSizes[j]) + { + s_blockSizeLookup[i] = (uint8)j; + } + else + { + ++j; + s_blockSizeLookup[i] = (uint8)j; + } + } + + s_blockSizeLookupInitialized = true; + } +} + +b2BlockAllocator::~b2BlockAllocator() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + b2Free(m_chunks); +} + +void* b2BlockAllocator::Allocate(int32 size) +{ + if (size == 0) + return NULL; + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + return b2Alloc(size); + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + + if (m_freeLists[index]) + { + b2Block* block = m_freeLists[index]; + m_freeLists[index] = block->next; + return block; + } + else + { + if (m_chunkCount == m_chunkSpace) + { + b2Chunk* oldChunks = m_chunks; + m_chunkSpace += b2_chunkArrayIncrement; + m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); + memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); + memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); + b2Free(oldChunks); + } + + b2Chunk* chunk = m_chunks + m_chunkCount; + chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); +#if defined(_DEBUG) + memset(chunk->blocks, 0xcd, b2_chunkSize); +#endif + int32 blockSize = s_blockSizes[index]; + chunk->blockSize = blockSize; + int32 blockCount = b2_chunkSize / blockSize; + b2Assert(blockCount * blockSize <= b2_chunkSize); + for (int32 i = 0; i < blockCount - 1; ++i) + { + b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); + b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); + block->next = next; + } + b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); + last->next = NULL; + + m_freeLists[index] = chunk->blocks->next; + ++m_chunkCount; + + return chunk->blocks; + } +} + +void b2BlockAllocator::Free(void* p, int32 size) +{ + if (size == 0) + { + return; + } + + b2Assert(0 < size); + + if (size > b2_maxBlockSize) + { + b2Free(p); + return; + } + + int32 index = s_blockSizeLookup[size]; + b2Assert(0 <= index && index < b2_blockSizes); + +#ifdef _DEBUG + // Verify the memory address and size is valid. + int32 blockSize = s_blockSizes[index]; + bool found = false; + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Chunk* chunk = m_chunks + i; + if (chunk->blockSize != blockSize) + { + b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || + (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); + } + else + { + if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) + { + found = true; + } + } + } + + b2Assert(found); + + memset(p, 0xfd, blockSize); +#endif + + b2Block* block = (b2Block*)p; + block->next = m_freeLists[index]; + m_freeLists[index] = block; +} + +void b2BlockAllocator::Clear() +{ + for (int32 i = 0; i < m_chunkCount; ++i) + { + b2Free(m_chunks[i].blocks); + } + + m_chunkCount = 0; + memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); + + memset(m_freeLists, 0, sizeof(m_freeLists)); +} diff --git a/external/Box2D/Common/b2BlockAllocator.h b/external/Box2D/Common/b2BlockAllocator.h new file mode 100644 index 0000000000..ec221fdf61 --- /dev/null +++ b/external/Box2D/Common/b2BlockAllocator.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_BLOCK_ALLOCATOR_H +#define B2_BLOCK_ALLOCATOR_H + +#include + +const int32 b2_chunkSize = 16 * 1024; +const int32 b2_maxBlockSize = 640; +const int32 b2_blockSizes = 14; +const int32 b2_chunkArrayIncrement = 128; + +struct b2Block; +struct b2Chunk; + +/// This is a small object allocator used for allocating small +/// objects that persist for more than one time step. +/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp +class b2BlockAllocator +{ +public: + b2BlockAllocator(); + ~b2BlockAllocator(); + + /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. + void* Allocate(int32 size); + + /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. + void Free(void* p, int32 size); + + void Clear(); + +private: + + b2Chunk* m_chunks; + int32 m_chunkCount; + int32 m_chunkSpace; + + b2Block* m_freeLists[b2_blockSizes]; + + static int32 s_blockSizes[b2_blockSizes]; + static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; + static bool s_blockSizeLookupInitialized; +}; + +#endif diff --git a/external/Box2D/Common/b2Draw.cpp b/external/Box2D/Common/b2Draw.cpp new file mode 100644 index 0000000000..cb760025e9 --- /dev/null +++ b/external/Box2D/Common/b2Draw.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +b2Draw::b2Draw() +{ + m_drawFlags = 0; +} + +void b2Draw::SetFlags(uint32 flags) +{ + m_drawFlags = flags; +} + +uint32 b2Draw::GetFlags() const +{ + return m_drawFlags; +} + +void b2Draw::AppendFlags(uint32 flags) +{ + m_drawFlags |= flags; +} + +void b2Draw::ClearFlags(uint32 flags) +{ + m_drawFlags &= ~flags; +} diff --git a/external/Box2D/Common/b2Draw.h b/external/Box2D/Common/b2Draw.h new file mode 100644 index 0000000000..b33cd8d38f --- /dev/null +++ b/external/Box2D/Common/b2Draw.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +/// Color for debug drawing. Each value has the range [0,1]. +struct b2Color +{ + b2Color() {} + b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} + void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } + float32 r, g, b; +}; + +/// Implement and register this class with a b2World to provide debug drawing of physics +/// entities in your game. +class b2Draw +{ +public: + b2Draw(); + + virtual ~b2Draw() {} + + enum + { + e_shapeBit = 0x0001, ///< draw shapes + e_jointBit = 0x0002, ///< draw joint connections + e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes + e_pairBit = 0x0008, ///< draw broad-phase pairs + e_centerOfMassBit = 0x0010 ///< draw center of mass frame + }; + + /// Set the drawing flags. + void SetFlags(uint32 flags); + + /// Get the drawing flags. + uint32 GetFlags() const; + + /// Append flags to the current flags. + void AppendFlags(uint32 flags); + + /// Clear flags from the current flags. + void ClearFlags(uint32 flags); + + /// Draw a closed polygon provided in CCW order. + virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a solid closed polygon provided in CCW order. + virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a circle. + virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; + + /// Draw a solid circle. + virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; + + /// Draw a line segment. + virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; + + /// Draw a transform. Choose your own length scale. + /// @param xf a transform. + virtual void DrawTransform(const b2Transform& xf) = 0; + +protected: + uint32 m_drawFlags; +}; diff --git a/external/Box2D/Common/b2GrowableStack.h b/external/Box2D/Common/b2GrowableStack.h new file mode 100644 index 0000000000..68809521f4 --- /dev/null +++ b/external/Box2D/Common/b2GrowableStack.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2010 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. +*/ + +#ifndef B2_GROWABLE_STACK_H +#define B2_GROWABLE_STACK_H +#include +#include + +/// This is a growable LIFO stack with an initial capacity of N. +/// If the stack size exceeds the initial capacity, the heap is used +/// to increase the size of the stack. +template +class b2GrowableStack +{ +public: + b2GrowableStack() + { + m_stack = m_array; + m_count = 0; + m_capacity = N; + } + + ~b2GrowableStack() + { + if (m_stack != m_array) + { + b2Free(m_stack); + m_stack = NULL; + } + } + + void Push(const T& element) + { + if (m_count == m_capacity) + { + T* old = m_stack; + m_capacity *= 2; + m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); + std::memcpy(m_stack, old, m_count * sizeof(T)); + if (old != m_array) + { + b2Free(old); + } + } + + m_stack[m_count] = element; + ++m_count; + } + + T Pop() + { + b2Assert(m_count > 0); + --m_count; + return m_stack[m_count]; + } + + int32 GetCount() + { + return m_count; + } + +private: + T* m_stack; + T m_array[N]; + int32 m_count; + int32 m_capacity; +}; + + +#endif diff --git a/external/Box2D/Common/b2Math.cpp b/external/Box2D/Common/b2Math.cpp new file mode 100644 index 0000000000..15d68fce96 --- /dev/null +++ b/external/Box2D/Common/b2Math.cpp @@ -0,0 +1,94 @@ +/* +* 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 + +const b2Vec2 b2Vec2_zero(0.0f, 0.0f); + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec3 x; + x.x = det * b2Dot(b, b2Cross(ey, ez)); + x.y = det * b2Dot(ex, b2Cross(b, ez)); + x.z = det * b2Dot(ex, b2Cross(ey, b)); + return x; +} + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const +{ + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; +} + +/// +void b2Mat33::GetInverse22(b2Mat33* M) const +{ + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + + M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; + M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; + M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; +} + +/// Returns the zero matrix if singular. +void b2Mat33::GetSymInverse33(b2Mat33* M) const +{ + float32 det = b2Dot(ex, b2Cross(ey, ez)); + if (det != 0.0f) + { + det = 1.0f / det; + } + + float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; + float32 a22 = ey.y, a23 = ez.y; + float32 a33 = ez.z; + + M->ex.x = det * (a22 * a33 - a23 * a23); + M->ex.y = det * (a13 * a23 - a12 * a33); + M->ex.z = det * (a12 * a23 - a13 * a22); + + M->ey.x = M->ex.y; + M->ey.y = det * (a11 * a33 - a13 * a13); + M->ey.z = det * (a13 * a12 - a11 * a23); + + M->ez.x = M->ex.z; + M->ez.y = M->ey.z; + M->ez.z = det * (a11 * a22 - a12 * a12); +} diff --git a/external/Box2D/Common/b2Math.h b/external/Box2D/Common/b2Math.h new file mode 100644 index 0000000000..a6be671139 --- /dev/null +++ b/external/Box2D/Common/b2Math.h @@ -0,0 +1,738 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_MATH_H +#define B2_MATH_H + +#include + +#include +#ifndef SHP +#include +#else +#include +#endif +#include +#include + +using namespace std; + + +/// This function is used to ensure that a floating point number is +/// not a NaN or infinity. +inline bool b2IsValid(float32 x) +{ + if (x != x) + { + // NaN. + return false; + } + + float32 infinity = std::numeric_limits::infinity(); + return -infinity < x && x < infinity; +} + +/// This is a approximate yet fast inverse square-root. +inline float32 b2InvSqrt(float32 x) +{ + union + { + float32 x; + int32 i; + } convert; + + convert.x = x; + float32 xhalf = 0.5f * x; + convert.i = 0x5f3759df - (convert.i >> 1); + x = convert.x; + x = x * (1.5f - xhalf * x * x); + return x; +} + +#define b2Sqrt(x) std::sqrt(x) +#define b2Atan2(y, x) std::atan2(y, x) + +/// A 2D column vector. +struct b2Vec2 +{ + /// Default constructor does nothing (for performance). + b2Vec2() {} + + /// Construct using coordinates. + b2Vec2(float32 x, float32 y) : x(x), y(y) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_) { x = x_; y = y_; } + + /// Negate this vector. + b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } + + /// Read from and indexed element. + float32 operator () (int32 i) const + { + return (&x)[i]; + } + + /// Write to an indexed element. + float32& operator () (int32 i) + { + return (&x)[i]; + } + + /// Add a vector to this vector. + void operator += (const b2Vec2& v) + { + x += v.x; y += v.y; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec2& v) + { + x -= v.x; y -= v.y; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 a) + { + x *= a; y *= a; + } + + /// Get the length of this vector (the norm). + float32 Length() const + { + return b2Sqrt(x * x + y * y); + } + + /// Get the length squared. For performance, use this instead of + /// b2Vec2::Length (if possible). + float32 LengthSquared() const + { + return x * x + y * y; + } + + /// Convert this vector into a unit vector. Returns the length. + float32 Normalize() + { + float32 length = Length(); + if (length < b2_epsilon) + { + return 0.0f; + } + float32 invLength = 1.0f / length; + x *= invLength; + y *= invLength; + + return length; + } + + /// Does this vector contain finite coordinates? + bool IsValid() const + { + return b2IsValid(x) && b2IsValid(y); + } + + /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) + b2Vec2 Skew() const + { + return b2Vec2(-y, x); + } + + float32 x, y; +}; + +/// A 2D column vector with 3 elements. +struct b2Vec3 +{ + /// Default constructor does nothing (for performance). + b2Vec3() {} + + /// Construct using coordinates. + b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } + + /// Negate this vector. + b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } + + /// Add a vector to this vector. + void operator += (const b2Vec3& v) + { + x += v.x; y += v.y; z += v.z; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec3& v) + { + x -= v.x; y -= v.y; z -= v.z; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 s) + { + x *= s; y *= s; z *= s; + } + + float32 x, y, z; +}; + +/// A 2-by-2 matrix. Stored in column-major order. +struct b2Mat22 +{ + /// The default constructor does nothing (for performance). + b2Mat22() {} + + /// Construct this matrix using columns. + b2Mat22(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Construct this matrix using scalars. + b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) + { + ex.x = a11; ex.y = a21; + ey.x = a12; ey.y = a22; + } + + /// Initialize this matrix using columns. + void Set(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Set this to the identity matrix. + void SetIdentity() + { + ex.x = 1.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 1.0f; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.x = 0.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 0.0f; + } + + b2Mat22 GetInverse() const + { + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + b2Mat22 B; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + B.ex.x = det * d; B.ey.x = -det * b; + B.ex.y = -det * c; B.ey.y = det * a; + return B; + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec2 Solve(const b2Vec2& b) const + { + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; + } + + b2Vec2 ex, ey; +}; + +/// A 3-by-3 matrix. Stored in column-major order. +struct b2Mat33 +{ + /// The default constructor does nothing (for performance). + b2Mat33() {} + + /// Construct this matrix using columns. + b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) + { + ex = c1; + ey = c2; + ez = c3; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.SetZero(); + ey.SetZero(); + ez.SetZero(); + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec3 Solve33(const b2Vec3& b) const; + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. Solve only the upper + /// 2-by-2 matrix equation. + b2Vec2 Solve22(const b2Vec2& b) const; + + /// Get the inverse of this matrix as a 2-by-2. + /// Returns the zero matrix if singular. + void GetInverse22(b2Mat33* M) const; + + /// Get the symmetric inverse of this matrix as a 3-by-3. + /// Returns the zero matrix if singular. + void GetSymInverse33(b2Mat33* M) const; + + b2Vec3 ex, ey, ez; +}; + +/// Rotation +struct b2Rot +{ + b2Rot() {} + + /// Initialize from an angle in radians + explicit b2Rot(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set using an angle in radians. + void Set(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set to the identity rotation + void SetIdentity() + { + s = 0.0f; + c = 1.0f; + } + + /// Get the angle in radians + float32 GetAngle() const + { + return b2Atan2(s, c); + } + + /// Get the x-axis + b2Vec2 GetXAxis() const + { + return b2Vec2(c, s); + } + + /// Get the u-axis + b2Vec2 GetYAxis() const + { + return b2Vec2(-s, c); + } + + /// Sine and cosine + float32 s, c; +}; + +/// A transform contains translation and rotation. It is used to represent +/// the position and orientation of rigid frames. +struct b2Transform +{ + /// The default constructor does nothing. + b2Transform() {} + + /// Initialize using a position vector and a rotation. + b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} + + /// Set this to the identity transform. + void SetIdentity() + { + p.SetZero(); + q.SetIdentity(); + } + + /// Set this based on the position and angle. + void Set(const b2Vec2& position, float32 angle) + { + p = position; + q.Set(angle); + } + + b2Vec2 p; + b2Rot q; +}; + +/// This describes the motion of a body/shape for TOI computation. +/// Shapes are defined with respect to the body origin, which may +/// no coincide with the center of mass. However, to support dynamics +/// we must interpolate the center of mass position. +struct b2Sweep +{ + /// Get the interpolated transform at a specific time. + /// @param beta is a factor in [0,1], where 0 indicates alpha0. + void GetTransform(b2Transform* xfb, float32 beta) const; + + /// Advance the sweep forward, yielding a new initial state. + /// @param alpha the new initial time. + void Advance(float32 alpha); + + /// Normalize the angles. + void Normalize(); + + b2Vec2 localCenter; ///< local center of mass position + b2Vec2 c0, c; ///< center world positions + float32 a0, a; ///< world angles + + /// Fraction of the current time step in the range [0,1] + /// c0 and a0 are the positions at alpha0. + float32 alpha0; +}; + +/// Useful constant +extern const b2Vec2 b2Vec2_zero; + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.x + a.y * b.y; +} + +/// Perform the cross product on two vectors. In 2D this produces a scalar. +inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.y - a.y * b.x; +} + +/// Perform the cross product on a vector and a scalar. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) +{ + return b2Vec2(s * a.y, -s * a.x); +} + +/// Perform the cross product on a scalar and a vector. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) +{ + return b2Vec2(-s * a.y, s * a.x); +} + +/// Multiply a matrix times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another. +inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another (inverse transform). +inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); +} + +/// Add two vectors component-wise. +inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x + b.x, a.y + b.y); +} + +/// Subtract two vectors component-wise. +inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x - b.x, a.y - b.y); +} + +inline b2Vec2 operator * (float32 s, const b2Vec2& a) +{ + return b2Vec2(s * a.x, s * a.y); +} + +inline bool operator == (const b2Vec2& a, const b2Vec2& b) +{ + return a.x == b.x && a.y == b.y; +} + +inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return c.Length(); +} + +inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return b2Dot(c, c); +} + +inline b2Vec3 operator * (float32 s, const b2Vec3& a) +{ + return b2Vec3(s * a.x, s * a.y, s * a.z); +} + +/// Add two vectors component-wise. +inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +/// Subtract two vectors component-wise. +inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +/// Perform the cross product on two vectors. +inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(A.ex + B.ex, A.ey + B.ey); +} + +// A * B +inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); +} + +// A^T * B +inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) +{ + b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); + b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); + return b2Mat22(c1, c2); +} + +/// Multiply a matrix times a vector. +inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) +{ + return v.x * A.ex + v.y * A.ey + v.z * A.ez; +} + +/// Multiply a matrix times a vector. +inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply two rotations: q * r +inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) +{ + // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] + // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] + // s = qs * rc + qc * rs + // c = qc * rc - qs * rs + b2Rot qr; + qr.s = q.s * r.c + q.c * r.s; + qr.c = q.c * r.c - q.s * r.s; + return qr; +} + +/// Transpose multiply two rotations: qT * r +inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) +{ + // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] + // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] + // s = qc * rs - qs * rc + // c = qc * rc + qs * rs + b2Rot qr; + qr.s = q.c * r.s - q.s * r.c; + qr.c = q.c * r.c + q.s * r.s; + return qr; +} + +/// Rotate a vector +inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); +} + +/// Inverse rotate a vector +inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); +} + +inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) +{ + float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; + float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; + + return b2Vec2(x, y); +} + +inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) +{ + float32 px = v.x - T.p.x; + float32 py = v.y - T.p.y; + float32 x = (T.q.c * px + T.q.s * py); + float32 y = (-T.q.s * px + T.q.c * py); + + return b2Vec2(x, y); +} + +// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p +// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p +inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2Mul(A.q, B.q); + C.p = b2Mul(A.q, B.p) + A.p; + return C; +} + +// v2 = A.q' * (B.q * v1 + B.p - A.p) +// = A.q' * B.q * v1 + A.q' * (B.p - A.p) +inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2MulT(A.q, B.q); + C.p = b2MulT(A.q, B.p - A.p); + return C; +} + +template +inline T b2Abs(T a) +{ + return a > T(0) ? a : -a; +} + +inline b2Vec2 b2Abs(const b2Vec2& a) +{ + return b2Vec2(b2Abs(a.x), b2Abs(a.y)); +} + +inline b2Mat22 b2Abs(const b2Mat22& A) +{ + return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); +} + +template +inline T b2Min(T a, T b) +{ + return a < b ? a : b; +} + +inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); +} + +template +inline T b2Max(T a, T b) +{ + return a > b ? a : b; +} + +inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); +} + +template +inline T b2Clamp(T a, T low, T high) +{ + return b2Max(low, b2Min(a, high)); +} + +inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) +{ + return b2Max(low, b2Min(a, high)); +} + +template inline void b2Swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + +/// "Next Largest Power of 2 +/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm +/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with +/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next +/// largest power of 2. For a 32-bit value:" +inline uint32 b2NextPowerOfTwo(uint32 x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +inline bool b2IsPowerOfTwo(uint32 x) +{ + bool result = x > 0 && (x & (x - 1)) == 0; + return result; +} + +inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const +{ + xf->p = (1.0f - beta) * c0 + beta * c; + float32 angle = (1.0f - beta) * a0 + beta * a; + xf->q.Set(angle); + + // Shift to origin + xf->p -= b2Mul(xf->q, localCenter); +} + +inline void b2Sweep::Advance(float32 alpha) +{ + b2Assert(alpha0 < 1.0f); + float32 beta = (alpha - alpha0) / (1.0f - alpha0); + c0 = (1.0f - beta) * c0 + beta * c; + a0 = (1.0f - beta) * a0 + beta * a; + alpha0 = alpha; +} + +/// Normalize an angle in radians to be between -pi and pi +inline void b2Sweep::Normalize() +{ + float32 twoPi = 2.0f * b2_pi; + float32 d = twoPi * floorf(a0 / twoPi); + a0 -= d; + a -= d; +} + +#endif diff --git a/external/Box2D/Common/b2Settings.cpp b/external/Box2D/Common/b2Settings.cpp new file mode 100644 index 0000000000..84d6f1d0e4 --- /dev/null +++ b/external/Box2D/Common/b2Settings.cpp @@ -0,0 +1,61 @@ +/* +* Copyright (c) 2006-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 +#ifdef SHP +#include +#include +#include +#include +#else +#include +#include +#include +#endif + + +using namespace std; + + +b2Version b2_version = {2, 2, 1}; + +// Memory allocators. Modify these to use your own allocator. +void* b2Alloc(int32 size) +{ + return malloc(size); +} + +void b2Free(void* mem) +{ + free(mem); +} + +// You can modify this to use your logging facility. +void b2Log(const char* string, ...) +{ +#if defined(SHP) + #ifdef _DEBUG + __App_info(__PRETTY_FUNCTION__ , __LINE__, string); + #endif +#else + va_list args; + va_start(args, string); + vprintf(string, args); + va_end(args); +#endif +} diff --git a/external/Box2D/Common/b2Settings.h b/external/Box2D/Common/b2Settings.h new file mode 100644 index 0000000000..aaf4b12ccf --- /dev/null +++ b/external/Box2D/Common/b2Settings.h @@ -0,0 +1,150 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_SETTINGS_H +#define B2_SETTINGS_H + +#include +#include + +#define B2_NOT_USED(x) ((void)(x)) +#define b2Assert(A) assert(A) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef float float32; +typedef double float64; + +#define b2_maxFloat FLT_MAX +#define b2_epsilon FLT_EPSILON +#define b2_pi 3.14159265359f + +/// @file +/// Global tuning constants based on meters-kilograms-seconds (MKS) units. +/// + +// Collision + +/// The maximum number of contact points between two convex shapes. Do +/// not change this value. +#define b2_maxManifoldPoints 2 + +/// The maximum number of vertices on a convex polygon. You cannot increase +/// this too much because b2BlockAllocator has a maximum object size. +#define b2_maxPolygonVertices 8 + +/// This is used to fatten AABBs in the dynamic tree. This allows proxies +/// to move by a small amount without triggering a tree adjustment. +/// This is in meters. +#define b2_aabbExtension 0.1f + +/// This is used to fatten AABBs in the dynamic tree. This is used to predict +/// the future position based on the current displacement. +/// This is a dimensionless multiplier. +#define b2_aabbMultiplier 2.0f + +/// A small length used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_linearSlop 0.005f + +/// A small angle used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_angularSlop (2.0f / 180.0f * b2_pi) + +/// The radius of the polygon/edge shape skin. This should not be modified. Making +/// this smaller means polygons will have an insufficient buffer for continuous collision. +/// Making it larger may create artifacts for vertex collision. +#define b2_polygonRadius (2.0f * b2_linearSlop) + +/// Maximum number of sub-steps per contact in continuous physics simulation. +#define b2_maxSubSteps 8 + + +// Dynamics + +/// Maximum number of contacts to be handled to solve a TOI impact. +#define b2_maxTOIContacts 32 + +/// A velocity threshold for elastic collisions. Any collision with a relative linear +/// velocity below this threshold will be treated as inelastic. +#define b2_velocityThreshold 1.0f + +/// The maximum linear position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxLinearCorrection 0.2f + +/// The maximum angular position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) + +/// The maximum linear velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxTranslation 2.0f +#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) + +/// The maximum angular velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxRotation (0.5f * b2_pi) +#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) + +/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so +/// that overlap is removed in one time step. However using values close to 1 often lead +/// to overshoot. +#define b2_baumgarte 0.2f +#define b2_toiBaugarte 0.75f + + +// Sleep + +/// The time that a body must be still before it will go to sleep. +#define b2_timeToSleep 0.5f + +/// A body cannot sleep if its linear velocity is above this tolerance. +#define b2_linearSleepTolerance 0.01f + +/// A body cannot sleep if its angular velocity is above this tolerance. +#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) + +// Memory Allocation + +/// Implement this function to use your own memory allocator. +void* b2Alloc(int32 size); + +/// If you implement b2Alloc, you should also implement this function. +void b2Free(void* mem); + +/// Logging function. +void b2Log(const char* string, ...); + +/// Version numbering scheme. +/// See http://en.wikipedia.org/wiki/Software_versioning +struct b2Version +{ + int32 major; ///< significant changes + int32 minor; ///< incremental changes + int32 revision; ///< bug fixes +}; + +/// Current version. +extern b2Version b2_version; + +#endif diff --git a/external/Box2D/Common/b2StackAllocator.cpp b/external/Box2D/Common/b2StackAllocator.cpp new file mode 100644 index 0000000000..3caa5d9127 --- /dev/null +++ b/external/Box2D/Common/b2StackAllocator.cpp @@ -0,0 +1,83 @@ +/* +* Copyright (c) 2006-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 +#include + +b2StackAllocator::b2StackAllocator() +{ + m_index = 0; + m_allocation = 0; + m_maxAllocation = 0; + m_entryCount = 0; +} + +b2StackAllocator::~b2StackAllocator() +{ + b2Assert(m_index == 0); + b2Assert(m_entryCount == 0); +} + +void* b2StackAllocator::Allocate(int32 size) +{ + b2Assert(m_entryCount < b2_maxStackEntries); + + b2StackEntry* entry = m_entries + m_entryCount; + entry->size = size; + if (m_index + size > b2_stackSize) + { + entry->data = (char*)b2Alloc(size); + entry->usedMalloc = true; + } + else + { + entry->data = m_data + m_index; + entry->usedMalloc = false; + m_index += size; + } + + m_allocation += size; + m_maxAllocation = b2Max(m_maxAllocation, m_allocation); + ++m_entryCount; + + return entry->data; +} + +void b2StackAllocator::Free(void* p) +{ + b2Assert(m_entryCount > 0); + b2StackEntry* entry = m_entries + m_entryCount - 1; + b2Assert(p == entry->data); + if (entry->usedMalloc) + { + b2Free(p); + } + else + { + m_index -= entry->size; + } + m_allocation -= entry->size; + --m_entryCount; + + p = NULL; +} + +int32 b2StackAllocator::GetMaxAllocation() const +{ + return m_maxAllocation; +} diff --git a/external/Box2D/Common/b2StackAllocator.h b/external/Box2D/Common/b2StackAllocator.h new file mode 100644 index 0000000000..6140d0d802 --- /dev/null +++ b/external/Box2D/Common/b2StackAllocator.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_STACK_ALLOCATOR_H +#define B2_STACK_ALLOCATOR_H + +#include + +const int32 b2_stackSize = 100 * 1024; // 100k +const int32 b2_maxStackEntries = 32; + +struct b2StackEntry +{ + char* data; + int32 size; + bool usedMalloc; +}; + +// This is a stack allocator used for fast per step allocations. +// You must nest allocate/free pairs. The code will assert +// if you try to interleave multiple allocate/free pairs. +class b2StackAllocator +{ +public: + b2StackAllocator(); + ~b2StackAllocator(); + + void* Allocate(int32 size); + void Free(void* p); + + int32 GetMaxAllocation() const; + +private: + + char m_data[b2_stackSize]; + int32 m_index; + + int32 m_allocation; + int32 m_maxAllocation; + + b2StackEntry m_entries[b2_maxStackEntries]; + int32 m_entryCount; +}; + +#endif diff --git a/external/Box2D/Common/b2Timer.cpp b/external/Box2D/Common/b2Timer.cpp new file mode 100644 index 0000000000..b2bee94513 --- /dev/null +++ b/external/Box2D/Common/b2Timer.cpp @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +#if defined(_WIN32) && !defined(SHP) + +float64 b2Timer::s_invFrequency = 0.0f; + +#include + +b2Timer::b2Timer() +{ + LARGE_INTEGER largeInteger; + + if (s_invFrequency == 0.0f) + { + QueryPerformanceFrequency(&largeInteger); + s_invFrequency = float64(largeInteger.QuadPart); + if (s_invFrequency > 0.0f) + { + s_invFrequency = 1000.0f / s_invFrequency; + } + } + + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +void b2Timer::Reset() +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + m_start = float64(largeInteger.QuadPart); +} + +float32 b2Timer::GetMilliseconds() const +{ + LARGE_INTEGER largeInteger; + QueryPerformanceCounter(&largeInteger); + float64 count = float64(largeInteger.QuadPart); + float32 ms = float32(s_invFrequency * (count - m_start)); + return ms; +} + +#elif defined(__linux__) || defined (__APPLE__) + +#include + +b2Timer::b2Timer() +{ + Reset(); +} + +void b2Timer::Reset() +{ + timeval t; + gettimeofday(&t, 0); + m_start_sec = t.tv_sec; + m_start_msec = t.tv_usec * 0.001f; +} + +float32 b2Timer::GetMilliseconds() const +{ + timeval t; + gettimeofday(&t, 0); + return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; +} + +#else + +b2Timer::b2Timer() +{ +} + +void b2Timer::Reset() +{ +} + +float32 b2Timer::GetMilliseconds() const +{ + return 0.0f; +} + +#endif diff --git a/external/Box2D/Common/b2Timer.h b/external/Box2D/Common/b2Timer.h new file mode 100644 index 0000000000..053a107a56 --- /dev/null +++ b/external/Box2D/Common/b2Timer.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 + +/// Timer for profiling. This has platform specific code and may +/// not work on every platform. +class b2Timer +{ +public: + + /// Constructor + b2Timer(); + + /// Reset the timer. + void Reset(); + + /// Get the time since construction or the last reset. + float32 GetMilliseconds() const; + +private: + +#if defined(_WIN32) + float64 m_start; + static float64 s_invFrequency; +#elif defined(__linux__) || defined (__APPLE__) + unsigned long m_start_sec; + unsigned long m_start_msec; +#endif +}; diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp new file mode 100644 index 0000000000..4ae4c41cd3 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); + return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); + allocator->Free(contact, sizeof(b2ChainAndCircleContact)); +} + +b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndCircle( manifold, &edge, xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h new file mode 100644 index 0000000000..1cf601a61f --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H +#define B2_CHAIN_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp new file mode 100644 index 0000000000..8116c34d1b --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); + return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); +} + +void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); + allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); +} + +b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) +: b2Contact(fixtureA, indexA, fixtureB, indexB) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); + b2EdgeShape edge; + chain->GetChildEdge(&edge, m_indexA); + b2CollideEdgeAndPolygon( manifold, &edge, xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h new file mode 100644 index 0000000000..381c49b844 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H +#define B2_CHAIN_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2ChainAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp new file mode 100644 index 0000000000..2436da5132 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2CircleContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2CircleContact)); + return new (mem) b2CircleContact(fixtureA, fixtureB); +} + +void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2CircleContact*)contact)->~b2CircleContact(); + allocator->Free(contact, sizeof(b2CircleContact)); +} + +b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideCircles(manifold, + (b2CircleShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2CircleContact.h b/external/Box2D/Dynamics/Contacts/b2CircleContact.h new file mode 100644 index 0000000000..6da056ae0d --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2CircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CIRCLE_CONTACT_H +#define B2_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2CircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2CircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2Contact.cpp b/external/Box2D/Dynamics/Contacts/b2Contact.cpp new file mode 100644 index 0000000000..2389af6434 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2Contact.cpp @@ -0,0 +1,240 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; +bool b2Contact::s_initialized = false; + +void b2Contact::InitializeRegisters() +{ + AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); + AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); + AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); + AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); + AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); + AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); + AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); +} + +void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, + b2Shape::Type type1, b2Shape::Type type2) +{ + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + s_registers[type1][type2].createFcn = createFcn; + s_registers[type1][type2].destroyFcn = destoryFcn; + s_registers[type1][type2].primary = true; + + if (type1 != type2) + { + s_registers[type2][type1].createFcn = createFcn; + s_registers[type2][type1].destroyFcn = destoryFcn; + s_registers[type2][type1].primary = false; + } +} + +b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) +{ + if (s_initialized == false) + { + InitializeRegisters(); + s_initialized = true; + } + + b2Shape::Type type1 = fixtureA->GetType(); + b2Shape::Type type2 = fixtureB->GetType(); + + b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); + b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); + + b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; + if (createFcn) + { + if (s_registers[type1][type2].primary) + { + return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); + } + else + { + return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); + } + } + else + { + return NULL; + } +} + +void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + b2Assert(s_initialized == true); + + if (contact->m_manifold.pointCount > 0) + { + contact->GetFixtureA()->GetBody()->SetAwake(true); + contact->GetFixtureB()->GetBody()->SetAwake(true); + } + + b2Shape::Type typeA = contact->GetFixtureA()->GetType(); + b2Shape::Type typeB = contact->GetFixtureB()->GetType(); + + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); + + b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; + destroyFcn(contact, allocator); +} + +b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) +{ + m_flags = e_enabledFlag; + + m_fixtureA = fA; + m_fixtureB = fB; + + m_indexA = indexA; + m_indexB = indexB; + + m_manifold.pointCount = 0; + + m_prev = NULL; + m_next = NULL; + + m_nodeA.contact = NULL; + m_nodeA.prev = NULL; + m_nodeA.next = NULL; + m_nodeA.other = NULL; + + m_nodeB.contact = NULL; + m_nodeB.prev = NULL; + m_nodeB.next = NULL; + m_nodeB.other = NULL; + + m_toiCount = 0; + + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +// Update the contact manifold and touching status. +// Note: do not assume the fixture AABBs are overlapping or are valid. +void b2Contact::Update(b2ContactListener* listener) +{ + b2Manifold oldManifold = m_manifold; + + // Re-enable this contact. + m_flags |= e_enabledFlag; + + bool touching = false; + bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; + + bool sensorA = m_fixtureA->IsSensor(); + bool sensorB = m_fixtureB->IsSensor(); + bool sensor = sensorA || sensorB; + + b2Body* bodyA = m_fixtureA->GetBody(); + b2Body* bodyB = m_fixtureB->GetBody(); + const b2Transform& xfA = bodyA->GetTransform(); + const b2Transform& xfB = bodyB->GetTransform(); + + // Is this contact a sensor? + if (sensor) + { + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); + + // Sensors don't generate manifolds. + m_manifold.pointCount = 0; + } + else + { + Evaluate(&m_manifold, xfA, xfB); + touching = m_manifold.pointCount > 0; + + // Match old contact ids to new contact ids and copy the + // stored impulses to warm start the solver. + for (int32 i = 0; i < m_manifold.pointCount; ++i) + { + b2ManifoldPoint* mp2 = m_manifold.points + i; + mp2->normalImpulse = 0.0f; + mp2->tangentImpulse = 0.0f; + b2ContactID id2 = mp2->id; + + for (int32 j = 0; j < oldManifold.pointCount; ++j) + { + b2ManifoldPoint* mp1 = oldManifold.points + j; + + if (mp1->id.key == id2.key) + { + mp2->normalImpulse = mp1->normalImpulse; + mp2->tangentImpulse = mp1->tangentImpulse; + break; + } + } + } + + if (touching != wasTouching) + { + bodyA->SetAwake(true); + bodyB->SetAwake(true); + } + } + + if (touching) + { + m_flags |= e_touchingFlag; + } + else + { + m_flags &= ~e_touchingFlag; + } + + if (wasTouching == false && touching == true && listener) + { + listener->BeginContact(this); + } + + if (wasTouching == true && touching == false && listener) + { + listener->EndContact(this); + } + + if (sensor == false && touching && listener) + { + listener->PreSolve(this, &oldManifold); + } +} diff --git a/external/Box2D/Dynamics/Contacts/b2Contact.h b/external/Box2D/Dynamics/Contacts/b2Contact.h new file mode 100644 index 0000000000..20d9403ce7 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2Contact.h @@ -0,0 +1,331 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_H +#define B2_CONTACT_H + +#include +#include +#include +#include + +class b2Body; +class b2Contact; +class b2Fixture; +class b2World; +class b2BlockAllocator; +class b2StackAllocator; +class b2ContactListener; + +/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. +/// For example, anything slides on ice. +inline float32 b2MixFriction(float32 friction1, float32 friction2) +{ + return std::sqrt(friction1 * friction2); +} + +/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. +/// For example, a superball bounces on anything. +inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) +{ + return restitution1 > restitution2 ? restitution1 : restitution2; +} + +typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, + b2BlockAllocator* allocator); +typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); + +struct b2ContactRegister +{ + b2ContactCreateFcn* createFcn; + b2ContactDestroyFcn* destroyFcn; + bool primary; +}; + +/// A contact edge is used to connect bodies and contacts together +/// in a contact graph where each body is a node and each contact +/// is an edge. A contact edge belongs to a doubly linked list +/// maintained in each attached body. Each contact has two contact +/// nodes, one for each attached body. +struct b2ContactEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Contact* contact; ///< the contact + b2ContactEdge* prev; ///< the previous contact edge in the body's contact list + b2ContactEdge* next; ///< the next contact edge in the body's contact list +}; + +/// The class manages contact between two shapes. A contact exists for each overlapping +/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist +/// that has no contact points. +class b2Contact +{ +public: + + /// Get the contact manifold. Do not modify the manifold unless you understand the + /// internals of Box2D. + b2Manifold* GetManifold(); + const b2Manifold* GetManifold() const; + + /// Get the world manifold. + void GetWorldManifold(b2WorldManifold* worldManifold) const; + + /// Is this contact touching? + bool IsTouching() const; + + /// Enable/disable this contact. This can be used inside the pre-solve + /// contact listener. The contact is only disabled for the current + /// time step (or sub-step in continuous collisions). + void SetEnabled(bool flag); + + /// Has this contact been disabled? + bool IsEnabled() const; + + /// Get the next contact in the world's contact list. + b2Contact* GetNext(); + const b2Contact* GetNext() const; + + /// Get fixture A in this contact. + b2Fixture* GetFixtureA(); + const b2Fixture* GetFixtureA() const; + + /// Get the child primitive index for fixture A. + int32 GetChildIndexA() const; + + /// Get fixture B in this contact. + b2Fixture* GetFixtureB(); + const b2Fixture* GetFixtureB() const; + + /// Get the child primitive index for fixture B. + int32 GetChildIndexB() const; + + /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. + /// This value persists until set or reset. + void SetFriction(float32 friction); + + /// Get the friction. + float32 GetFriction() const; + + /// Reset the friction mixture to the default value. + void ResetFriction(); + + /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. + /// The value persists until you set or reset. + void SetRestitution(float32 restitution); + + /// Get the restitution. + float32 GetRestitution() const; + + /// Reset the restitution to the default value. + void ResetRestitution(); + + /// Evaluate this contact with your own manifold and transforms. + virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; + +protected: + friend class b2ContactManager; + friend class b2World; + friend class b2ContactSolver; + friend class b2Body; + friend class b2Fixture; + + // Flags stored in m_flags + enum + { + // Used when crawling contact graph when forming islands. + e_islandFlag = 0x0001, + + // Set when the shapes are touching. + e_touchingFlag = 0x0002, + + // This contact can be disabled (by user) + e_enabledFlag = 0x0004, + + // This contact needs filtering because a fixture filter was changed. + e_filterFlag = 0x0008, + + // This bullet contact had a TOI event + e_bulletHitFlag = 0x0010, + + // This contact has a valid TOI in m_toi + e_toiFlag = 0x0020 + }; + + /// Flag this contact for filtering. Filtering will occur the next time step. + void FlagForFiltering(); + + static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, + b2Shape::Type typeA, b2Shape::Type typeB); + static void InitializeRegisters(); + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} + b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + virtual ~b2Contact() {} + + void Update(b2ContactListener* listener); + + static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; + static bool s_initialized; + + uint32 m_flags; + + // World pool and list pointers. + b2Contact* m_prev; + b2Contact* m_next; + + // Nodes for connecting bodies. + b2ContactEdge m_nodeA; + b2ContactEdge m_nodeB; + + b2Fixture* m_fixtureA; + b2Fixture* m_fixtureB; + + int32 m_indexA; + int32 m_indexB; + + b2Manifold m_manifold; + + int32 m_toiCount; + float32 m_toi; + + float32 m_friction; + float32 m_restitution; +}; + +inline b2Manifold* b2Contact::GetManifold() +{ + return &m_manifold; +} + +inline const b2Manifold* b2Contact::GetManifold() const +{ + return &m_manifold; +} + +inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const +{ + const b2Body* bodyA = m_fixtureA->GetBody(); + const b2Body* bodyB = m_fixtureB->GetBody(); + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + + worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); +} + +inline void b2Contact::SetEnabled(bool flag) +{ + if (flag) + { + m_flags |= e_enabledFlag; + } + else + { + m_flags &= ~e_enabledFlag; + } +} + +inline bool b2Contact::IsEnabled() const +{ + return (m_flags & e_enabledFlag) == e_enabledFlag; +} + +inline bool b2Contact::IsTouching() const +{ + return (m_flags & e_touchingFlag) == e_touchingFlag; +} + +inline b2Contact* b2Contact::GetNext() +{ + return m_next; +} + +inline const b2Contact* b2Contact::GetNext() const +{ + return m_next; +} + +inline b2Fixture* b2Contact::GetFixtureA() +{ + return m_fixtureA; +} + +inline const b2Fixture* b2Contact::GetFixtureA() const +{ + return m_fixtureA; +} + +inline b2Fixture* b2Contact::GetFixtureB() +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexA() const +{ + return m_indexA; +} + +inline const b2Fixture* b2Contact::GetFixtureB() const +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexB() const +{ + return m_indexB; +} + +inline void b2Contact::FlagForFiltering() +{ + m_flags |= e_filterFlag; +} + +inline void b2Contact::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Contact::GetFriction() const +{ + return m_friction; +} + +inline void b2Contact::ResetFriction() +{ + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); +} + +inline void b2Contact::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline float32 b2Contact::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Contact::ResetRestitution() +{ + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp b/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp new file mode 100644 index 0000000000..0dc740342a --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ContactSolver.cpp @@ -0,0 +1,832 @@ +/* +* Copyright (c) 2006-2011 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 + +#include +#include +#include +#include +#include + +#define B2_DEBUG_SOLVER 0 + +struct b2ContactPositionConstraint +{ + b2Vec2 localPoints[b2_maxManifoldPoints]; + b2Vec2 localNormal; + b2Vec2 localPoint; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + b2Vec2 localCenterA, localCenterB; + float32 invIA, invIB; + b2Manifold::Type type; + float32 radiusA, radiusB; + int32 pointCount; +}; + +b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) +{ + m_step = def->step; + m_allocator = def->allocator; + m_count = def->count; + m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); + m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); + m_positions = def->positions; + m_velocities = def->velocities; + m_contacts = def->contacts; + + // Initialize position independent portions of the constraints. + for (int32 i = 0; i < m_count; ++i) + { + b2Contact* contact = m_contacts[i]; + + b2Fixture* fixtureA = contact->m_fixtureA; + b2Fixture* fixtureB = contact->m_fixtureB; + b2Shape* shapeA = fixtureA->GetShape(); + b2Shape* shapeB = fixtureB->GetShape(); + float32 radiusA = shapeA->m_radius; + float32 radiusB = shapeB->m_radius; + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + b2Manifold* manifold = contact->GetManifold(); + + int32 pointCount = manifold->pointCount; + b2Assert(pointCount > 0); + + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + vc->friction = contact->m_friction; + vc->restitution = contact->m_restitution; + vc->indexA = bodyA->m_islandIndex; + vc->indexB = bodyB->m_islandIndex; + vc->invMassA = bodyA->m_invMass; + vc->invMassB = bodyB->m_invMass; + vc->invIA = bodyA->m_invI; + vc->invIB = bodyB->m_invI; + vc->contactIndex = i; + vc->pointCount = pointCount; + vc->K.SetZero(); + vc->normalMass.SetZero(); + + b2ContactPositionConstraint* pc = m_positionConstraints + i; + pc->indexA = bodyA->m_islandIndex; + pc->indexB = bodyB->m_islandIndex; + pc->invMassA = bodyA->m_invMass; + pc->invMassB = bodyB->m_invMass; + pc->localCenterA = bodyA->m_sweep.localCenter; + pc->localCenterB = bodyB->m_sweep.localCenter; + pc->invIA = bodyA->m_invI; + pc->invIB = bodyB->m_invI; + pc->localNormal = manifold->localNormal; + pc->localPoint = manifold->localPoint; + pc->pointCount = pointCount; + pc->radiusA = radiusA; + pc->radiusB = radiusB; + pc->type = manifold->type; + + for (int32 j = 0; j < pointCount; ++j) + { + b2ManifoldPoint* cp = manifold->points + j; + b2VelocityConstraintPoint* vcp = vc->points + j; + + if (m_step.warmStarting) + { + vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; + vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; + } + else + { + vcp->normalImpulse = 0.0f; + vcp->tangentImpulse = 0.0f; + } + + vcp->rA.SetZero(); + vcp->rB.SetZero(); + vcp->normalMass = 0.0f; + vcp->tangentMass = 0.0f; + vcp->velocityBias = 0.0f; + + pc->localPoints[j] = cp->localPoint; + } + } +} + +b2ContactSolver::~b2ContactSolver() +{ + m_allocator->Free(m_velocityConstraints); + m_allocator->Free(m_positionConstraints); +} + +// Initialize position dependent portions of the velocity constraints. +void b2ContactSolver::InitializeVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + float32 radiusA = pc->radiusA; + float32 radiusB = pc->radiusB; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + + float32 mA = vc->invMassA; + float32 mB = vc->invMassB; + float32 iA = vc->invIA; + float32 iB = vc->invIB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Assert(manifold->pointCount > 0); + + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2WorldManifold worldManifold; + worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); + + vc->normal = worldManifold.normal; + + int32 pointCount = vc->pointCount; + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + vcp->rA = worldManifold.points[j] - cA; + vcp->rB = worldManifold.points[j] - cB; + + float32 rnA = b2Cross(vcp->rA, vc->normal); + float32 rnB = b2Cross(vcp->rB, vc->normal); + + float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; + + b2Vec2 tangent = b2Cross(vc->normal, 1.0f); + + float32 rtA = b2Cross(vcp->rA, tangent); + float32 rtB = b2Cross(vcp->rB, tangent); + + float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; + + vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; + + // Setup a velocity bias for restitution. + vcp->velocityBias = 0.0f; + float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); + if (vRel < -b2_velocityThreshold) + { + vcp->velocityBias = -vc->restitution * vRel; + } + } + + // If we have two points, then prepare the block solver. + if (vc->pointCount == 2) + { + b2VelocityConstraintPoint* vcp1 = vc->points + 0; + b2VelocityConstraintPoint* vcp2 = vc->points + 1; + + float32 rn1A = b2Cross(vcp1->rA, vc->normal); + float32 rn1B = b2Cross(vcp1->rB, vc->normal); + float32 rn2A = b2Cross(vcp2->rA, vc->normal); + float32 rn2B = b2Cross(vcp2->rB, vc->normal); + + float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; + float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; + float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; + + // Ensure a reasonable condition number. + const float32 k_maxConditionNumber = 1000.0f; + if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) + { + // K is safe to invert. + vc->K.ex.Set(k11, k12); + vc->K.ey.Set(k12, k22); + vc->normalMass = vc->K.GetInverse(); + } + else + { + // The constraints are redundant, just use one. + // TODO_ERIN use deepest? + vc->pointCount = 1; + } + } + } +} + +void b2ContactSolver::WarmStart() +{ + // Warm start. + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; + wA -= iA * b2Cross(vcp->rA, P); + vA -= mA * P; + wB += iB * b2Cross(vcp->rB, P); + vB += mB * P; + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::SolveVelocityConstraints() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + + int32 indexA = vc->indexA; + int32 indexB = vc->indexB; + float32 mA = vc->invMassA; + float32 iA = vc->invIA; + float32 mB = vc->invMassB; + float32 iB = vc->invIB; + int32 pointCount = vc->pointCount; + + b2Vec2 vA = m_velocities[indexA].v; + float32 wA = m_velocities[indexA].w; + b2Vec2 vB = m_velocities[indexB].v; + float32 wB = m_velocities[indexB].w; + + b2Vec2 normal = vc->normal; + b2Vec2 tangent = b2Cross(normal, 1.0f); + float32 friction = vc->friction; + + b2Assert(pointCount == 1 || pointCount == 2); + + // Solve tangent constraints first because non-penetration is more important + // than friction. + for (int32 j = 0; j < pointCount; ++j) + { + b2VelocityConstraintPoint* vcp = vc->points + j; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute tangent force + float32 vt = b2Dot(dv, tangent); + float32 lambda = vcp->tangentMass * (-vt); + + // b2Clamp the accumulated force + float32 maxFriction = friction * vcp->normalImpulse; + float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); + lambda = newImpulse - vcp->tangentImpulse; + vcp->tangentImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * tangent; + + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + + // Solve normal constraints + if (vc->pointCount == 1) + { + b2VelocityConstraintPoint* vcp = vc->points + 0; + + // Relative velocity at contact + b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); + + // Compute normal impulse + float32 vn = b2Dot(dv, normal); + float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); + + // b2Clamp the accumulated impulse + float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); + lambda = newImpulse - vcp->normalImpulse; + vcp->normalImpulse = newImpulse; + + // Apply contact impulse + b2Vec2 P = lambda * normal; + vA -= mA * P; + wA -= iA * b2Cross(vcp->rA, P); + + vB += mB * P; + wB += iB * b2Cross(vcp->rB, P); + } + else + { + // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). + // Build the mini LCP for this contact patch + // + // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 + // + // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) + // b = vn0 - velocityBias + // + // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i + // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases + // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid + // solution that satisfies the problem is chosen. + // + // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires + // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). + // + // Substitute: + // + // x = a + d + // + // a := old total impulse + // x := new total impulse + // d := incremental impulse + // + // For the current iteration we extend the formula for the incremental impulse + // to compute the new total impulse: + // + // vn = A * d + b + // = A * (x - a) + b + // = A * x + b - A * a + // = A * x + b' + // b' = b - A * a; + + b2VelocityConstraintPoint* cp1 = vc->points + 0; + b2VelocityConstraintPoint* cp2 = vc->points + 1; + + b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); + b2Assert(a.x >= 0.0f && a.y >= 0.0f); + + // Relative velocity at contact + b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + float32 vn1 = b2Dot(dv1, normal); + float32 vn2 = b2Dot(dv2, normal); + + b2Vec2 b; + b.x = vn1 - cp1->velocityBias; + b.y = vn2 - cp2->velocityBias; + + // Compute b' + b -= b2Mul(vc->K, a); + + const float32 k_errorTol = 1e-3f; + B2_NOT_USED(k_errorTol); + + for (;;) + { + // + // Case 1: vn = 0 + // + // 0 = A * x + b' + // + // Solve for x: + // + // x = - inv(A) * b' + // + b2Vec2 x = - b2Mul(vc->normalMass, b); + + if (x.x >= 0.0f && x.y >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 2: vn1 = 0 and x2 = 0 + // + // 0 = a11 * x1 + a12 * 0 + b1' + // vn2 = a21 * x1 + a22 * 0 + b2' + // + x.x = - cp1->normalMass * b.x; + x.y = 0.0f; + vn1 = 0.0f; + vn2 = vc->K.ex.y * x.x + b.y; + + if (x.x >= 0.0f && vn2 >= 0.0f) + { + // Get the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); + + // Compute normal velocity + vn1 = b2Dot(dv1, normal); + + b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); +#endif + break; + } + + + // + // Case 3: vn2 = 0 and x1 = 0 + // + // vn1 = a11 * 0 + a12 * x2 + b1' + // 0 = a21 * 0 + a22 * x2 + b2' + // + x.x = 0.0f; + x.y = - cp2->normalMass * b.y; + vn1 = vc->K.ey.x * x.y + b.x; + vn2 = 0.0f; + + if (x.y >= 0.0f && vn1 >= 0.0f) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + +#if B2_DEBUG_SOLVER == 1 + // Postconditions + dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); + + // Compute normal velocity + vn2 = b2Dot(dv2, normal); + + b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); +#endif + break; + } + + // + // Case 4: x1 = 0 and x2 = 0 + // + // vn1 = b1 + // vn2 = b2; + x.x = 0.0f; + x.y = 0.0f; + vn1 = b.x; + vn2 = b.y; + + if (vn1 >= 0.0f && vn2 >= 0.0f ) + { + // Resubstitute for the incremental impulse + b2Vec2 d = x - a; + + // Apply incremental impulse + b2Vec2 P1 = d.x * normal; + b2Vec2 P2 = d.y * normal; + vA -= mA * (P1 + P2); + wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); + + vB += mB * (P1 + P2); + wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); + + // Accumulate + cp1->normalImpulse = x.x; + cp2->normalImpulse = x.y; + + break; + } + + // No solution, give up. This is hit sometimes, but it doesn't seem to matter. + break; + } + } + + m_velocities[indexA].v = vA; + m_velocities[indexA].w = wA; + m_velocities[indexB].v = vB; + m_velocities[indexB].w = wB; + } +} + +void b2ContactSolver::StoreImpulses() +{ + for (int32 i = 0; i < m_count; ++i) + { + b2ContactVelocityConstraint* vc = m_velocityConstraints + i; + b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); + + for (int32 j = 0; j < vc->pointCount; ++j) + { + manifold->points[j].normalImpulse = vc->points[j].normalImpulse; + manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; + } + } +} + +struct b2PositionSolverManifold +{ + void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) + { + b2Assert(pc->pointCount > 0); + + switch (pc->type) + { + case b2Manifold::e_circles: + { + b2Vec2 pointA = b2Mul(xfA, pc->localPoint); + b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); + normal = pointB - pointA; + normal.Normalize(); + point = 0.5f * (pointA + pointB); + separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; + } + break; + + case b2Manifold::e_faceA: + { + normal = b2Mul(xfA.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + } + break; + + case b2Manifold::e_faceB: + { + normal = b2Mul(xfB.q, pc->localNormal); + b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); + + b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); + separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; + point = clipPoint; + + // Ensure normal points from A to B + normal = -normal; + } + break; + } + } + + b2Vec2 normal; + b2Vec2 point; + float32 separation; +}; + +// Sequential solver. +bool b2ContactSolver::SolvePositionConstraints() +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + float32 mA = pc->invMassA; + float32 iA = pc->invIA; + b2Vec2 localCenterB = pc->localCenterB; + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + int32 pointCount = pc->pointCount; + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -3.0f * b2_linearSlop; +} + +// Sequential position solver for position constraints. +bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) +{ + float32 minSeparation = 0.0f; + + for (int32 i = 0; i < m_count; ++i) + { + b2ContactPositionConstraint* pc = m_positionConstraints + i; + + int32 indexA = pc->indexA; + int32 indexB = pc->indexB; + b2Vec2 localCenterA = pc->localCenterA; + b2Vec2 localCenterB = pc->localCenterB; + int32 pointCount = pc->pointCount; + + float32 mA = 0.0f; + float32 iA = 0.0f; + if (indexA == toiIndexA || indexA == toiIndexB) + { + mA = pc->invMassA; + iA = pc->invIA; + } + + float32 mB = pc->invMassB; + float32 iB = pc->invIB; + if (indexB == toiIndexA || indexB == toiIndexB) + { + mB = pc->invMassB; + iB = pc->invIB; + } + + b2Vec2 cA = m_positions[indexA].c; + float32 aA = m_positions[indexA].a; + + b2Vec2 cB = m_positions[indexB].c; + float32 aB = m_positions[indexB].a; + + // Solve normal constraints + for (int32 j = 0; j < pointCount; ++j) + { + b2Transform xfA, xfB; + xfA.q.Set(aA); + xfB.q.Set(aB); + xfA.p = cA - b2Mul(xfA.q, localCenterA); + xfB.p = cB - b2Mul(xfB.q, localCenterB); + + b2PositionSolverManifold psm; + psm.Initialize(pc, xfA, xfB, j); + b2Vec2 normal = psm.normal; + + b2Vec2 point = psm.point; + float32 separation = psm.separation; + + b2Vec2 rA = point - cA; + b2Vec2 rB = point - cB; + + // Track max constraint error. + minSeparation = b2Min(minSeparation, separation); + + // Prevent large corrections and allow slop. + float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); + + // Compute the effective mass. + float32 rnA = b2Cross(rA, normal); + float32 rnB = b2Cross(rB, normal); + float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; + + // Compute normal impulse + float32 impulse = K > 0.0f ? - C / K : 0.0f; + + b2Vec2 P = impulse * normal; + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + + m_positions[indexA].c = cA; + m_positions[indexA].a = aA; + + m_positions[indexB].c = cB; + m_positions[indexB].a = aB; + } + + // We can't expect minSpeparation >= -b2_linearSlop because we don't + // push the separation above -b2_linearSlop. + return minSeparation >= -1.5f * b2_linearSlop; +} diff --git a/external/Box2D/Dynamics/Contacts/b2ContactSolver.h b/external/Box2D/Dynamics/Contacts/b2ContactSolver.h new file mode 100644 index 0000000000..aef1987a9e --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2ContactSolver.h @@ -0,0 +1,94 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_SOLVER_H +#define B2_CONTACT_SOLVER_H + +#include +#include +#include + +class b2Contact; +class b2Body; +class b2StackAllocator; +struct b2ContactPositionConstraint; + +struct b2VelocityConstraintPoint +{ + b2Vec2 rA; + b2Vec2 rB; + float32 normalImpulse; + float32 tangentImpulse; + float32 normalMass; + float32 tangentMass; + float32 velocityBias; +}; + +struct b2ContactVelocityConstraint +{ + b2VelocityConstraintPoint points[b2_maxManifoldPoints]; + b2Vec2 normal; + b2Mat22 normalMass; + b2Mat22 K; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + float32 invIA, invIB; + float32 friction; + float32 restitution; + int32 pointCount; + int32 contactIndex; +}; + +struct b2ContactSolverDef +{ + b2TimeStep step; + b2Contact** contacts; + int32 count; + b2Position* positions; + b2Velocity* velocities; + b2StackAllocator* allocator; +}; + +class b2ContactSolver +{ +public: + b2ContactSolver(b2ContactSolverDef* def); + ~b2ContactSolver(); + + void InitializeVelocityConstraints(); + + void WarmStart(); + void SolveVelocityConstraints(); + void StoreImpulses(); + + bool SolvePositionConstraints(); + bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); + + b2TimeStep m_step; + b2Position* m_positions; + b2Velocity* m_velocities; + b2StackAllocator* m_allocator; + b2ContactPositionConstraint* m_positionConstraints; + b2ContactVelocityConstraint* m_velocityConstraints; + b2Contact** m_contacts; + int m_count; +}; + +#endif + diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp new file mode 100644 index 0000000000..aade42880a --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); + return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); +} + +void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); + allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); +} + +b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndCircle( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h new file mode 100644 index 0000000000..70771ec536 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H +#define B2_EDGE_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp new file mode 100644 index 0000000000..04ce394107 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-2010 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 +#include +#include + +#include +using namespace std; + +b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); + return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); +} + +void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); + allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); +} + +b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollideEdgeAndPolygon( manifold, + (b2EdgeShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h new file mode 100644 index 0000000000..f65f3acca9 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_EDGE_AND_POLYGON_CONTACT_H +#define B2_EDGE_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2EdgeAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp new file mode 100644 index 0000000000..961b26f38a --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2006-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 +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); + return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); +} + +void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); + allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); +} + +b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) +: b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); +} + +void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygonAndCircle( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2CircleShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h new file mode 100644 index 0000000000..7b1a5288b4 --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H +#define B2_POLYGON_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp b/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp new file mode 100644 index 0000000000..a2884a440d --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2PolygonContact.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include + +#include +using namespace std; + +b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) +{ + void* mem = allocator->Allocate(sizeof(b2PolygonContact)); + return new (mem) b2PolygonContact(fixtureA, fixtureB); +} + +void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) +{ + ((b2PolygonContact*)contact)->~b2PolygonContact(); + allocator->Free(contact, sizeof(b2PolygonContact)); +} + +b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) + : b2Contact(fixtureA, 0, fixtureB, 0) +{ + b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); + b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); +} + +void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) +{ + b2CollidePolygons( manifold, + (b2PolygonShape*)m_fixtureA->GetShape(), xfA, + (b2PolygonShape*)m_fixtureB->GetShape(), xfB); +} diff --git a/external/Box2D/Dynamics/Contacts/b2PolygonContact.h b/external/Box2D/Dynamics/Contacts/b2PolygonContact.h new file mode 100644 index 0000000000..302684232a --- /dev/null +++ b/external/Box2D/Dynamics/Contacts/b2PolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_POLYGON_CONTACT_H +#define B2_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class b2PolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp new file mode 100644 index 0000000000..b2d4bd006c --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2DistanceJoint.cpp @@ -0,0 +1,260 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// 1-D constrained system +// m (v2 - v1) = lambda +// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. +// x2 = x1 + h * v2 + +// 1-D mass-damper-spring system +// m (v2 - v1) + h * d * v2 + h * k * + +// C = norm(p2 - p1) - L +// u = (p2 - p1) / norm(p2 - p1) +// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// J = [-u -cross(r1, u) u cross(r2, u)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 + +void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, + const b2Vec2& anchor1, const b2Vec2& anchor2) +{ + bodyA = b1; + bodyB = b2; + localAnchorA = bodyA->GetLocalPoint(anchor1); + localAnchorB = bodyB->GetLocalPoint(anchor2); + b2Vec2 d = anchor2 - anchor1; + length = d.Length(); +} + +b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_length = def->length; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + m_impulse = 0.0f; + m_gamma = 0.0f; + m_bias = 0.0f; +} + +void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + // Handle singularity. + float32 length = m_u.Length(); + if (length > b2_linearSlop) + { + m_u *= 1.0f / length; + } + else + { + m_u.Set(0.0f, 0.0f); + } + + float32 crAu = b2Cross(m_rA, m_u); + float32 crBu = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; + + // Compute the effective mass matrix. + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (m_frequencyHz > 0.0f) + { + float32 C = length - m_length; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_mass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invMass += m_gamma; + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + } + else + { + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 Cdot = b2Dot(m_u, vpB - vpA); + + float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); + m_impulse += impulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) +{ + if (m_frequencyHz > 0.0f) + { + // There is no position correction for soft distance constraints. + return true; + } + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_length; + C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) < b2_linearSlop; +} + +b2Vec2 b2DistanceJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2DistanceJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +void b2DistanceJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2DistanceJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.length = %.15lef;\n", m_length); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2DistanceJoint.h b/external/Box2D/Dynamics/Joints/b2DistanceJoint.h new file mode 100644 index 0000000000..fc11476ff9 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2DistanceJoint.h @@ -0,0 +1,169 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_DISTANCE_JOINT_H +#define B2_DISTANCE_JOINT_H + +#include + +/// Distance joint definition. This requires defining an +/// anchor point on both bodies and the non-zero length of the +/// distance joint. The definition uses local anchor points +/// so that the initial configuration can violate the constraint +/// slightly. This helps when saving and loading a game. +/// @warning Do not use a zero or short length. +struct b2DistanceJointDef : public b2JointDef +{ + b2DistanceJointDef() + { + type = e_distanceJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + length = 1.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and length using the world + /// anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& anchorA, const b2Vec2& anchorB); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The natural length between the anchor points. + float32 length; + + /// The mass-spring-damper frequency in Hertz. A value of 0 + /// disables softness. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A distance joint constrains two points on two bodies +/// to remain at a fixed distance from each other. You can view +/// this as a massless, rigid rod. +class b2DistanceJoint : public b2Joint +{ +public: + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque given the inverse time step. + /// Unit is N*m. This is always zero for a distance joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/get the natural length. + /// Manipulating the length can lead to non-physical behavior when the frequency is zero. + void SetLength(float32 length); + float32 GetLength() const; + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2DistanceJoint(const b2DistanceJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_gamma; + float32 m_impulse; + float32 m_length; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +inline void b2DistanceJoint::SetLength(float32 length) +{ + m_length = length; +} + +inline float32 b2DistanceJoint::GetLength() const +{ + return m_length; +} + +inline void b2DistanceJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2DistanceJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +inline void b2DistanceJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2DistanceJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp new file mode 100644 index 0000000000..6e6018db10 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2FrictionJoint.cpp @@ -0,0 +1,251 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); +} + +b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + + m_maxForce = def->maxForce; + m_maxTorque = def->maxTorque; +} + +void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective mass matrix. + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; + K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; + + m_linearMass = K.GetInverse(); + + m_angularMass = iA + iB; + if (m_angularMass > 0.0f) + { + m_angularMass = 1.0f / m_angularMass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_linearImpulse *= data.step.dtRatio; + m_angularImpulse *= data.step.dtRatio; + + b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); + } + else + { + m_linearImpulse.SetZero(); + m_angularImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + float32 h = data.step.dt; + + // Solve angular friction + { + float32 Cdot = wB - wA; + float32 impulse = -m_angularMass * Cdot; + + float32 oldImpulse = m_angularImpulse; + float32 maxImpulse = h * m_maxTorque; + m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_angularImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve linear friction + { + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); + b2Vec2 oldImpulse = m_linearImpulse; + m_linearImpulse += impulse; + + float32 maxImpulse = h * m_maxForce; + + if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_linearImpulse.Normalize(); + m_linearImpulse *= maxImpulse; + } + + impulse = m_linearImpulse - oldImpulse; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + + return true; +} + +b2Vec2 b2FrictionJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2FrictionJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_linearImpulse; +} + +float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_angularImpulse; +} + +void b2FrictionJoint::SetMaxForce(float32 force) +{ + b2Assert(b2IsValid(force) && force >= 0.0f); + m_maxForce = force; +} + +float32 b2FrictionJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2FrictionJoint::SetMaxTorque(float32 torque) +{ + b2Assert(b2IsValid(torque) && torque >= 0.0f); + m_maxTorque = torque; +} + +float32 b2FrictionJoint::GetMaxTorque() const +{ + return m_maxTorque; +} + +void b2FrictionJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2FrictionJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); + b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2FrictionJoint.h b/external/Box2D/Dynamics/Joints/b2FrictionJoint.h new file mode 100644 index 0000000000..3ee40c6298 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2FrictionJoint.h @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_FRICTION_JOINT_H +#define B2_FRICTION_JOINT_H + +#include + +/// Friction joint definition. +struct b2FrictionJointDef : public b2JointDef +{ + b2FrictionJointDef() + { + type = e_frictionJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + maxForce = 0.0f; + maxTorque = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum friction force in N. + float32 maxForce; + + /// The maximum friction torque in N-m. + float32 maxTorque; +}; + +/// Friction joint. This is used for top-down friction. +/// It provides 2D translational friction and angular friction. +class b2FrictionJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set the maximum friction force in N. + void SetMaxForce(float32 force); + + /// Get the maximum friction force in N. + float32 GetMaxForce() const; + + /// Set the maximum friction torque in N*m. + void SetMaxTorque(float32 torque); + + /// Get the maximum friction torque in N*m. + float32 GetMaxTorque() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + + b2FrictionJoint(const b2FrictionJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + + // Solver shared + b2Vec2 m_linearImpulse; + float32 m_angularImpulse; + float32 m_maxForce; + float32 m_maxTorque; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat22 m_linearMass; + float32 m_angularMass; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2GearJoint.cpp b/external/Box2D/Dynamics/Joints/b2GearJoint.cpp new file mode 100644 index 0000000000..9741cdd5a4 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2GearJoint.cpp @@ -0,0 +1,423 @@ +/* +* Copyright (c) 2007-2011 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 +#include +#include +#include +#include + +// Gear Joint: +// C0 = (coordinate1 + ratio * coordinate2)_initial +// C = (coordinate1 + ratio * coordinate2) - C0 = 0 +// J = [J1 ratio * J2] +// K = J * invM * JT +// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T +// +// Revolute: +// coordinate = rotation +// Cdot = angularVelocity +// J = [0 0 1] +// K = J * invM * JT = invI +// +// Prismatic: +// coordinate = dot(p - pg, ug) +// Cdot = dot(v + cross(w, r), ug) +// J = [ug cross(r, ug)] +// K = J * invM * JT = invMass + invI * cross(r, ug)^2 + +b2GearJoint::b2GearJoint(const b2GearJointDef* def) +: b2Joint(def) +{ + m_joint1 = def->joint1; + m_joint2 = def->joint2; + + m_typeA = m_joint1->GetType(); + m_typeB = m_joint2->GetType(); + + b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); + b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); + + float32 coordinateA, coordinateB; + + // TODO_ERIN there might be some problem with the joint edges in b2Joint. + + m_bodyC = m_joint1->GetBodyA(); + m_bodyA = m_joint1->GetBodyB(); + + // Get geometry of joint1 + b2Transform xfA = m_bodyA->m_xf; + float32 aA = m_bodyA->m_sweep.a; + b2Transform xfC = m_bodyC->m_xf; + float32 aC = m_bodyC->m_sweep.a; + + if (m_typeA == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; + m_localAnchorC = revolute->m_localAnchorA; + m_localAnchorA = revolute->m_localAnchorB; + m_referenceAngleA = revolute->m_referenceAngle; + m_localAxisC.SetZero(); + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; + m_localAnchorC = prismatic->m_localAnchorA; + m_localAnchorA = prismatic->m_localAnchorB; + m_referenceAngleA = prismatic->m_referenceAngle; + m_localAxisC = prismatic->m_localXAxisA; + + b2Vec2 pC = m_localAnchorC; + b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + m_bodyD = m_joint2->GetBodyA(); + m_bodyB = m_joint2->GetBodyB(); + + // Get geometry of joint2 + b2Transform xfB = m_bodyB->m_xf; + float32 aB = m_bodyB->m_sweep.a; + b2Transform xfD = m_bodyD->m_xf; + float32 aD = m_bodyD->m_sweep.a; + + if (m_typeB == e_revoluteJoint) + { + b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; + m_localAnchorD = revolute->m_localAnchorA; + m_localAnchorB = revolute->m_localAnchorB; + m_referenceAngleB = revolute->m_referenceAngle; + m_localAxisD.SetZero(); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; + m_localAnchorD = prismatic->m_localAnchorA; + m_localAnchorB = prismatic->m_localAnchorB; + m_referenceAngleB = prismatic->m_referenceAngle; + m_localAxisD = prismatic->m_localXAxisA; + + b2Vec2 pD = m_localAnchorD; + b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + m_ratio = def->ratio; + + m_constant = coordinateA + m_ratio * coordinateB; + + m_impulse = 0.0f; +} + +void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_indexC = m_bodyC->m_islandIndex; + m_indexD = m_bodyD->m_islandIndex; + m_lcA = m_bodyA->m_sweep.localCenter; + m_lcB = m_bodyB->m_sweep.localCenter; + m_lcC = m_bodyC->m_sweep.localCenter; + m_lcD = m_bodyD->m_sweep.localCenter; + m_mA = m_bodyA->m_invMass; + m_mB = m_bodyB->m_invMass; + m_mC = m_bodyC->m_invMass; + m_mD = m_bodyD->m_invMass; + m_iA = m_bodyA->m_invI; + m_iB = m_bodyB->m_invI; + m_iC = m_bodyC->m_invI; + m_iD = m_bodyD->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + m_mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + m_JvAC.SetZero(); + m_JwA = 1.0f; + m_JwC = 1.0f; + m_mass += m_iA + m_iC; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + m_JvAC = u; + m_JwC = b2Cross(rC, u); + m_JwA = b2Cross(rA, u); + m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; + } + + if (m_typeB == e_revoluteJoint) + { + m_JvBD.SetZero(); + m_JwB = m_ratio; + m_JwD = m_ratio; + m_mass += m_ratio * m_ratio * (m_iB + m_iD); + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + m_JvBD = m_ratio * u; + m_JwD = m_ratio * b2Cross(rD, u); + m_JwB = m_ratio * b2Cross(rB, u); + m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; + } + + // Compute effective mass. + m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; + + if (data.step.warmStarting) + { + vA += (m_mA * m_impulse) * m_JvAC; + wA += m_iA * m_impulse * m_JwA; + vB += (m_mB * m_impulse) * m_JvBD; + wB += m_iB * m_impulse * m_JwB; + vC -= (m_mC * m_impulse) * m_JvAC; + wC -= m_iC * m_impulse * m_JwC; + vD -= (m_mD * m_impulse) * m_JvBD; + wD -= m_iD * m_impulse * m_JwD; + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + b2Vec2 vC = data.velocities[m_indexC].v; + float32 wC = data.velocities[m_indexC].w; + b2Vec2 vD = data.velocities[m_indexD].v; + float32 wD = data.velocities[m_indexD].w; + + float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); + Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); + + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + vA += (m_mA * impulse) * m_JvAC; + wA += m_iA * impulse * m_JwA; + vB += (m_mB * impulse) * m_JvBD; + wB += m_iB * impulse * m_JwB; + vC -= (m_mC * impulse) * m_JvAC; + wC -= m_iC * impulse * m_JwC; + vD -= (m_mD * impulse) * m_JvBD; + wD -= m_iD * impulse * m_JwD; + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; + data.velocities[m_indexC].v = vC; + data.velocities[m_indexC].w = wC; + data.velocities[m_indexD].v = vD; + data.velocities[m_indexD].w = wD; +} + +bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 cC = data.positions[m_indexC].c; + float32 aC = data.positions[m_indexC].a; + b2Vec2 cD = data.positions[m_indexD].c; + float32 aD = data.positions[m_indexD].a; + + b2Rot qA(aA), qB(aB), qC(aC), qD(aD); + + float32 linearError = 0.0f; + + float32 coordinateA, coordinateB; + + b2Vec2 JvAC, JvBD; + float32 JwA, JwB, JwC, JwD; + float32 mass = 0.0f; + + if (m_typeA == e_revoluteJoint) + { + JvAC.SetZero(); + JwA = 1.0f; + JwC = 1.0f; + mass += m_iA + m_iC; + + coordinateA = aA - aC - m_referenceAngleA; + } + else + { + b2Vec2 u = b2Mul(qC, m_localAxisC); + b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); + JvAC = u; + JwC = b2Cross(rC, u); + JwA = b2Cross(rA, u); + mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; + + b2Vec2 pC = m_localAnchorC - m_lcC; + b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); + coordinateA = b2Dot(pA - pC, m_localAxisC); + } + + if (m_typeB == e_revoluteJoint) + { + JvBD.SetZero(); + JwB = m_ratio; + JwD = m_ratio; + mass += m_ratio * m_ratio * (m_iB + m_iD); + + coordinateB = aB - aD - m_referenceAngleB; + } + else + { + b2Vec2 u = b2Mul(qD, m_localAxisD); + b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); + JvBD = m_ratio * u; + JwD = m_ratio * b2Cross(rD, u); + JwB = m_ratio * b2Cross(rB, u); + mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; + + b2Vec2 pD = m_localAnchorD - m_lcD; + b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); + coordinateB = b2Dot(pB - pD, m_localAxisD); + } + + float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; + + float32 impulse = 0.0f; + if (mass > 0.0f) + { + impulse = -C / mass; + } + + cA += m_mA * impulse * JvAC; + aA += m_iA * impulse * JwA; + cB += m_mB * impulse * JvBD; + aB += m_iB * impulse * JwB; + cC -= m_mC * impulse * JvAC; + aC -= m_iC * impulse * JwC; + cD -= m_mD * impulse * JvBD; + aD -= m_iD * impulse * JwD; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + data.positions[m_indexC].c = cC; + data.positions[m_indexC].a = aC; + data.positions[m_indexD].c = cD; + data.positions[m_indexD].a = aD; + + // TODO_ERIN not implemented + return linearError < b2_linearSlop; +} + +b2Vec2 b2GearJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2GearJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_JvAC; + return inv_dt * P; +} + +float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const +{ + float32 L = m_impulse * m_JwA; + return inv_dt * L; +} + +void b2GearJoint::SetRatio(float32 ratio) +{ + b2Assert(b2IsValid(ratio)); + m_ratio = ratio; +} + +float32 b2GearJoint::GetRatio() const +{ + return m_ratio; +} + +void b2GearJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + int32 index1 = m_joint1->m_index; + int32 index2 = m_joint2->m_index; + + b2Log(" b2GearJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.joint1 = joints[%d];\n", index1); + b2Log(" jd.joint2 = joints[%d];\n", index2); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2GearJoint.h b/external/Box2D/Dynamics/Joints/b2GearJoint.h new file mode 100644 index 0000000000..f926bf6ef1 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2GearJoint.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_GEAR_JOINT_H +#define B2_GEAR_JOINT_H + +#include + +/// Gear joint definition. This definition requires two existing +/// revolute or prismatic joints (any combination will work). +struct b2GearJointDef : public b2JointDef +{ + b2GearJointDef() + { + type = e_gearJoint; + joint1 = NULL; + joint2 = NULL; + ratio = 1.0f; + } + + /// The first revolute/prismatic joint attached to the gear joint. + b2Joint* joint1; + + /// The second revolute/prismatic joint attached to the gear joint. + b2Joint* joint2; + + /// The gear ratio. + /// @see b2GearJoint for explanation. + float32 ratio; +}; + +/// A gear joint is used to connect two joints together. Either joint +/// can be a revolute or prismatic joint. You specify a gear ratio +/// to bind the motions together: +/// coordinate1 + ratio * coordinate2 = constant +/// The ratio can be negative or positive. If one joint is a revolute joint +/// and the other joint is a prismatic joint, then the ratio will have units +/// of length or units of 1/length. +/// @warning You have to manually destroy the gear joint if joint1 or joint2 +/// is destroyed. +class b2GearJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first joint. + b2Joint* GetJoint1() { return m_joint1; } + + /// Get the second joint. + b2Joint* GetJoint2() { return m_joint2; } + + /// Set/Get the gear ratio. + void SetRatio(float32 ratio); + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2GearJoint(const b2GearJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Joint* m_joint1; + b2Joint* m_joint2; + + b2JointType m_typeA; + b2JointType m_typeB; + + // Body A is connected to body C + // Body B is connected to body D + b2Body* m_bodyC; + b2Body* m_bodyD; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localAnchorC; + b2Vec2 m_localAnchorD; + + b2Vec2 m_localAxisC; + b2Vec2 m_localAxisD; + + float32 m_referenceAngleA; + float32 m_referenceAngleB; + + float32 m_constant; + float32 m_ratio; + + float32 m_impulse; + + // Solver temp + int32 m_indexA, m_indexB, m_indexC, m_indexD; + b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; + float32 m_mA, m_mB, m_mC, m_mD; + float32 m_iA, m_iB, m_iC, m_iD; + b2Vec2 m_JvAC, m_JvBD; + float32 m_JwA, m_JwB, m_JwC, m_JwD; + float32 m_mass; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2Joint.cpp b/external/Box2D/Dynamics/Joints/b2Joint.cpp new file mode 100644 index 0000000000..6853b09f0b --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2Joint.cpp @@ -0,0 +1,199 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) +{ + b2Joint* joint = NULL; + + switch (def->type) + { + case e_distanceJoint: + { + void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); + joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); + } + break; + + case e_mouseJoint: + { + void* mem = allocator->Allocate(sizeof(b2MouseJoint)); + joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); + } + break; + + case e_prismaticJoint: + { + void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); + joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); + } + break; + + case e_revoluteJoint: + { + void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); + joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); + } + break; + + case e_pulleyJoint: + { + void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); + joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); + } + break; + + case e_gearJoint: + { + void* mem = allocator->Allocate(sizeof(b2GearJoint)); + joint = new (mem) b2GearJoint((b2GearJointDef*)def); + } + break; + + case e_wheelJoint: + { + void* mem = allocator->Allocate(sizeof(b2WheelJoint)); + joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); + } + break; + + case e_weldJoint: + { + void* mem = allocator->Allocate(sizeof(b2WeldJoint)); + joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); + } + break; + + case e_frictionJoint: + { + void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); + joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); + } + break; + + case e_ropeJoint: + { + void* mem = allocator->Allocate(sizeof(b2RopeJoint)); + joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); + } + break; + + default: + b2Assert(false); + break; + } + + return joint; +} + +void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) +{ + joint->~b2Joint(); + switch (joint->m_type) + { + case e_distanceJoint: + allocator->Free(joint, sizeof(b2DistanceJoint)); + break; + + case e_mouseJoint: + allocator->Free(joint, sizeof(b2MouseJoint)); + break; + + case e_prismaticJoint: + allocator->Free(joint, sizeof(b2PrismaticJoint)); + break; + + case e_revoluteJoint: + allocator->Free(joint, sizeof(b2RevoluteJoint)); + break; + + case e_pulleyJoint: + allocator->Free(joint, sizeof(b2PulleyJoint)); + break; + + case e_gearJoint: + allocator->Free(joint, sizeof(b2GearJoint)); + break; + + case e_wheelJoint: + allocator->Free(joint, sizeof(b2WheelJoint)); + break; + + case e_weldJoint: + allocator->Free(joint, sizeof(b2WeldJoint)); + break; + + case e_frictionJoint: + allocator->Free(joint, sizeof(b2FrictionJoint)); + break; + + case e_ropeJoint: + allocator->Free(joint, sizeof(b2RopeJoint)); + break; + + default: + b2Assert(false); + break; + } +} + +b2Joint::b2Joint(const b2JointDef* def) +{ + b2Assert(def->bodyA != def->bodyB); + + m_type = def->type; + m_prev = NULL; + m_next = NULL; + m_bodyA = def->bodyA; + m_bodyB = def->bodyB; + m_index = 0; + m_collideConnected = def->collideConnected; + m_islandFlag = false; + m_userData = def->userData; + + m_edgeA.joint = NULL; + m_edgeA.other = NULL; + m_edgeA.prev = NULL; + m_edgeA.next = NULL; + + m_edgeB.joint = NULL; + m_edgeB.other = NULL; + m_edgeB.prev = NULL; + m_edgeB.next = NULL; +} + +bool b2Joint::IsActive() const +{ + return m_bodyA->IsActive() && m_bodyB->IsActive(); +} diff --git a/external/Box2D/Dynamics/Joints/b2Joint.h b/external/Box2D/Dynamics/Joints/b2Joint.h new file mode 100644 index 0000000000..b4ea576665 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2Joint.h @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_JOINT_H +#define B2_JOINT_H + +#include + +class b2Body; +class b2Joint; +struct b2SolverData; +class b2BlockAllocator; + +enum b2JointType +{ + e_unknownJoint, + e_revoluteJoint, + e_prismaticJoint, + e_distanceJoint, + e_pulleyJoint, + e_mouseJoint, + e_gearJoint, + e_wheelJoint, + e_weldJoint, + e_frictionJoint, + e_ropeJoint +}; + +enum b2LimitState +{ + e_inactiveLimit, + e_atLowerLimit, + e_atUpperLimit, + e_equalLimits +}; + +struct b2Jacobian +{ + b2Vec2 linear; + float32 angularA; + float32 angularB; +}; + +/// A joint edge is used to connect bodies and joints together +/// in a joint graph where each body is a node and each joint +/// is an edge. A joint edge belongs to a doubly linked list +/// maintained in each attached body. Each joint has two joint +/// nodes, one for each attached body. +struct b2JointEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Joint* joint; ///< the joint + b2JointEdge* prev; ///< the previous joint edge in the body's joint list + b2JointEdge* next; ///< the next joint edge in the body's joint list +}; + +/// Joint definitions are used to construct joints. +struct b2JointDef +{ + b2JointDef() + { + type = e_unknownJoint; + userData = NULL; + bodyA = NULL; + bodyB = NULL; + collideConnected = false; + } + + /// The joint type is set automatically for concrete joint types. + b2JointType type; + + /// Use this to attach application specific data to your joints. + void* userData; + + /// The first attached body. + b2Body* bodyA; + + /// The second attached body. + b2Body* bodyB; + + /// Set this flag to true if the attached bodies should collide. + bool collideConnected; +}; + +/// The base joint class. Joints are used to constraint two bodies together in +/// various fashions. Some joints also feature limits and motors. +class b2Joint +{ +public: + + /// Get the type of the concrete joint. + b2JointType GetType() const; + + /// Get the first body attached to this joint. + b2Body* GetBodyA(); + + /// Get the second body attached to this joint. + b2Body* GetBodyB(); + + /// Get the anchor point on bodyA in world coordinates. + virtual b2Vec2 GetAnchorA() const = 0; + + /// Get the anchor point on bodyB in world coordinates. + virtual b2Vec2 GetAnchorB() const = 0; + + /// Get the reaction force on bodyB at the joint anchor in Newtons. + virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; + + /// Get the reaction torque on bodyB in N*m. + virtual float32 GetReactionTorque(float32 inv_dt) const = 0; + + /// Get the next joint the world joint list. + b2Joint* GetNext(); + const b2Joint* GetNext() const; + + /// Get the user data pointer. + void* GetUserData() const; + + /// Set the user data pointer. + void SetUserData(void* data); + + /// Short-cut function to determine if either body is inactive. + bool IsActive() const; + + /// Get collide connected. + /// Note: modifying the collide connect flag won't work correctly because + /// the flag is only checked when fixture AABBs begin to overlap. + bool GetCollideConnected() const; + + /// Dump this joint to the log file. + virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } + +protected: + friend class b2World; + friend class b2Body; + friend class b2Island; + friend class b2GearJoint; + + static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); + static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); + + b2Joint(const b2JointDef* def); + virtual ~b2Joint() {} + + virtual void InitVelocityConstraints(const b2SolverData& data) = 0; + virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; + + // This returns true if the position errors are within tolerance. + virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; + + b2JointType m_type; + b2Joint* m_prev; + b2Joint* m_next; + b2JointEdge m_edgeA; + b2JointEdge m_edgeB; + b2Body* m_bodyA; + b2Body* m_bodyB; + + int32 m_index; + + bool m_islandFlag; + bool m_collideConnected; + + void* m_userData; +}; + +inline b2JointType b2Joint::GetType() const +{ + return m_type; +} + +inline b2Body* b2Joint::GetBodyA() +{ + return m_bodyA; +} + +inline b2Body* b2Joint::GetBodyB() +{ + return m_bodyB; +} + +inline b2Joint* b2Joint::GetNext() +{ + return m_next; +} + +inline const b2Joint* b2Joint::GetNext() const +{ + return m_next; +} + +inline void* b2Joint::GetUserData() const +{ + return m_userData; +} + +inline void b2Joint::SetUserData(void* data) +{ + m_userData = data; +} + +inline bool b2Joint::GetCollideConnected() const +{ + return m_collideConnected; +} + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp new file mode 100644 index 0000000000..237d9d519a --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2MouseJoint.cpp @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include + +// p = attached point, m = mouse point +// C = p - m +// Cdot = v +// = v + cross(w, r) +// J = [I r_skew] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) +: b2Joint(def) +{ + b2Assert(def->target.IsValid()); + b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); + b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); + b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); + + m_targetA = def->target; + m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); + + m_maxForce = def->maxForce; + m_impulse.SetZero(); + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_beta = 0.0f; + m_gamma = 0.0f; +} + +void b2MouseJoint::SetTarget(const b2Vec2& target) +{ + if (m_bodyB->IsAwake() == false) + { + m_bodyB->SetAwake(true); + } + m_targetA = target; +} + +const b2Vec2& b2MouseJoint::GetTarget() const +{ + return m_targetA; +} + +void b2MouseJoint::SetMaxForce(float32 force) +{ + m_maxForce = force; +} + +float32 b2MouseJoint::GetMaxForce() const +{ + return m_maxForce; +} + +void b2MouseJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +float32 b2MouseJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +void b2MouseJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +float32 b2MouseJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexB = m_bodyB->m_islandIndex; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassB = m_bodyB->m_invMass; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qB(aB); + + float32 mass = m_bodyB->GetMass(); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * mass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = mass * (omega * omega); + + // magic formulas + // gamma has units of inverse mass. + // beta has units of inverse time. + float32 h = data.step.dt; + b2Assert(d + h * k > b2_epsilon); + m_gamma = h * (d + h * k); + if (m_gamma != 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + m_beta = h * k * m_gamma; + + // Compute the effective mass matrix. + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] + // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] + // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] + b2Mat22 K; + K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; + K.ex.y = -m_invIB * m_rB.x * m_rB.y; + K.ey.x = K.ex.y; + K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; + + m_mass = K.GetInverse(); + + m_C = cB + m_rB - m_targetA; + m_C *= m_beta; + + // Cheat with some damping + wB *= 0.98f; + + if (data.step.warmStarting) + { + m_impulse *= data.step.dtRatio; + vB += m_invMassB * m_impulse; + wB += m_invIB * b2Cross(m_rB, m_impulse); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = v + cross(w, r) + b2Vec2 Cdot = vB + b2Cross(wB, m_rB); + b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); + + b2Vec2 oldImpulse = m_impulse; + m_impulse += impulse; + float32 maxImpulse = data.step.dt * m_maxForce; + if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) + { + m_impulse *= maxImpulse / m_impulse.Length(); + } + impulse = m_impulse - oldImpulse; + + vB += m_invMassB * impulse; + wB += m_invIB * b2Cross(m_rB, impulse); + + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) +{ + B2_NOT_USED(data); + return true; +} + +b2Vec2 b2MouseJoint::GetAnchorA() const +{ + return m_targetA; +} + +b2Vec2 b2MouseJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * m_impulse; +} + +float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * 0.0f; +} diff --git a/external/Box2D/Dynamics/Joints/b2MouseJoint.h b/external/Box2D/Dynamics/Joints/b2MouseJoint.h new file mode 100644 index 0000000000..1bbc194f4c --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2MouseJoint.h @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2006-2007 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. +*/ + +#ifndef B2_MOUSE_JOINT_H +#define B2_MOUSE_JOINT_H + +#include + +/// Mouse joint definition. This requires a world target point, +/// tuning parameters, and the time step. +struct b2MouseJointDef : public b2JointDef +{ + b2MouseJointDef() + { + type = e_mouseJoint; + target.Set(0.0f, 0.0f); + maxForce = 0.0f; + frequencyHz = 5.0f; + dampingRatio = 0.7f; + } + + /// The initial world target point. This is assumed + /// to coincide with the body anchor initially. + b2Vec2 target; + + /// The maximum constraint force that can be exerted + /// to move the candidate body. Usually you will express + /// as some multiple of the weight (multiplier * mass * gravity). + float32 maxForce; + + /// The response speed. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A mouse joint is used to make a point on a body track a +/// specified world point. This a soft constraint with a maximum +/// force. This allows the constraint to stretch and without +/// applying huge forces. +/// NOTE: this joint is not documented in the manual because it was +/// developed to be used in the testbed. If you want to learn how to +/// use the mouse joint, look at the testbed. +class b2MouseJoint : public b2Joint +{ +public: + + /// Implements b2Joint. + b2Vec2 GetAnchorA() const; + + /// Implements b2Joint. + b2Vec2 GetAnchorB() const; + + /// Implements b2Joint. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Implements b2Joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Use this to update the target point. + void SetTarget(const b2Vec2& target); + const b2Vec2& GetTarget() const; + + /// Set/get the maximum force in Newtons. + void SetMaxForce(float32 force); + float32 GetMaxForce() const; + + /// Set/get the frequency in Hertz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get the damping ratio (dimensionless). + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// The mouse joint does not support dumping. + void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } + +protected: + friend class b2Joint; + + b2MouseJoint(const b2MouseJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorB; + b2Vec2 m_targetA; + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_beta; + + // Solver shared + b2Vec2 m_impulse; + float32 m_maxForce; + float32 m_gamma; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rB; + b2Vec2 m_localCenterB; + float32 m_invMassB; + float32 m_invIB; + b2Mat22 m_mass; + b2Vec2 m_C; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp new file mode 100644 index 0000000000..4849f729f5 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp @@ -0,0 +1,637 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Linear constraint (point-to-line) +// d = p2 - p1 = x2 + r2 - x1 - r1 +// C = dot(perp, d) +// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) +// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) +// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] +// +// Angular constraint +// C = a2 - a1 + a_initial +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// +// K = J * invM * JT +// +// J = [-a -s1 a s2] +// [0 -1 0 1] +// a = perp +// s1 = cross(d + r1, a) = cross(p2 - x1, a) +// s2 = cross(r2, a) = cross(p2 - x2, a) + + +// Motor/Limit linear constraint +// C = dot(ax1, d) +// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) +// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] + +// Block Solver +// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even +// when the mass has poor distribution (leading to large torques about the joint anchor points). +// +// The Jacobian has 3 rows: +// J = [-uT -s1 uT s2] // linear +// [0 -1 0 1] // angular +// [-vT -a1 vT a2] // limit +// +// u = perp +// v = axis +// s1 = cross(d + r1, u), s2 = cross(r2, u) +// a1 = cross(d + r1, v), a2 = cross(r2, v) + +// M * (v2 - v1) = JT * df +// J * v2 = bias +// +// v2 = v1 + invM * JT * df +// J * (v1 + invM * JT * df) = bias +// K * df = bias - J * v1 = -Cdot +// K = J * invM * JT +// Cdot = J * v1 - bias +// +// Now solve for f2. +// df = f2 - f1 +// K * (f2 - f1) = -Cdot +// f2 = invK * (-Cdot) + f1 +// +// Clamp accumulated limit impulse. +// lower: f2(3) = max(f2(3), 0) +// upper: f2(3) = min(f2(3), 0) +// +// Solve for correct f2(1:2) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 +// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) +// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) +// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) +// +// Now compute impulse to be applied: +// df = f2 - f1 + +void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localXAxisA.Normalize(); + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + + m_lowerTranslation = def->lowerTranslation; + m_upperTranslation = def->upperTranslation; + m_maxMotorForce = def->maxMotorForce; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; + + m_axis.SetZero(); + m_perp.SetZero(); +} + +void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute motor Jacobian and effective mass. + { + m_axis = b2Mul(qA, m_localXAxisA); + m_a1 = b2Cross(d + rA, m_axis); + m_a2 = b2Cross(rB, m_axis); + + m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + + // Prismatic constraint. + { + m_perp = b2Mul(qA, m_localYAxisA); + + m_s1 = b2Cross(d + rA, m_perp); + m_s2 = b2Cross(rB, m_perp); + + float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; + float32 k12 = iA * m_s1 + iB * m_s2; + float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For bodies with fixed rotation. + k22 = 1.0f; + } + float32 k23 = iA * m_a1 + iB * m_a2; + float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; + + m_K.ex.Set(k11, k12, k13); + m_K.ey.Set(k12, k22, k23); + m_K.ez.Set(k13, k23, k33); + } + + // Compute motor and limit terms. + if (m_enableLimit) + { + float32 jointTranslation = b2Dot(m_axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + m_limitState = e_equalLimits; + } + else if (jointTranslation <= m_lowerTranslation) + { + if (m_limitState != e_atLowerLimit) + { + m_limitState = e_atLowerLimit; + m_impulse.z = 0.0f; + } + } + else if (jointTranslation >= m_upperTranslation) + { + if (m_limitState != e_atUpperLimit) + { + m_limitState = e_atUpperLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + + if (m_enableMotor == false) + { + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; + float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; + float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Solve linear motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits) + { + float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + float32 impulse = m_motorMass * (m_motorSpeed - Cdot); + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorForce; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + b2Vec2 P = impulse * m_axis; + float32 LA = impulse * m_a1; + float32 LB = impulse * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + b2Vec2 Cdot1; + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (m_enableLimit && m_limitState != e_inactiveLimit) + { + // Solve prismatic and limit constraint in block form. + float32 Cdot2; + Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 f1 = m_impulse; + b2Vec3 df = m_K.Solve33(-Cdot); + m_impulse += df; + + if (m_limitState == e_atLowerLimit) + { + m_impulse.z = b2Max(m_impulse.z, 0.0f); + } + else if (m_limitState == e_atUpperLimit) + { + m_impulse.z = b2Min(m_impulse.z, 0.0f); + } + + // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) + b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); + b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); + m_impulse.x = f2r.x; + m_impulse.y = f2r.y; + + df = m_impulse - f1; + + b2Vec2 P = df.x * m_perp + df.z * m_axis; + float32 LA = df.x * m_s1 + df.y + df.z * m_a1; + float32 LB = df.x * m_s2 + df.y + df.z * m_a2; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + else + { + // Limit is inactive, just solve the prismatic constraint in block form. + b2Vec2 df = m_K.Solve22(-Cdot1); + m_impulse.x += df.x; + m_impulse.y += df.y; + + b2Vec2 P = df.x * m_perp; + float32 LA = df.x * m_s1 + df.y; + float32 LB = df.x * m_s2 + df.y; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + + b2Vec2 Cdot10 = Cdot1; + + Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; + Cdot1.y = wB - wA; + + if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f) + { + b2Vec2 test = b2Mul22(m_K, df); + Cdot1.x += 0.0f; + } + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + // Compute fresh Jacobians + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + b2Vec2 axis = b2Mul(qA, m_localXAxisA); + float32 a1 = b2Cross(d + rA, axis); + float32 a2 = b2Cross(rB, axis); + b2Vec2 perp = b2Mul(qA, m_localYAxisA); + + float32 s1 = b2Cross(d + rA, perp); + float32 s2 = b2Cross(rB, perp); + + b2Vec3 impulse; + b2Vec2 C1; + C1.x = b2Dot(perp, d); + C1.y = aB - aA - m_referenceAngle; + + float32 linearError = b2Abs(C1.x); + float32 angularError = b2Abs(C1.y); + + bool active = false; + float32 C2 = 0.0f; + if (m_enableLimit) + { + float32 translation = b2Dot(axis, d); + if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) + { + // Prevent large angular corrections + C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); + linearError = b2Max(linearError, b2Abs(translation)); + active = true; + } + else if (translation <= m_lowerTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); + linearError = b2Max(linearError, m_lowerTranslation - translation); + active = true; + } + else if (translation >= m_upperTranslation) + { + // Prevent large linear corrections and allow some slop. + C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); + linearError = b2Max(linearError, translation - m_upperTranslation); + active = true; + } + } + + if (active) + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k13 = iA * s1 * a1 + iB * s2 * a2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + // For fixed rotation + k22 = 1.0f; + } + float32 k23 = iA * a1 + iB * a2; + float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; + + b2Mat33 K; + K.ex.Set(k11, k12, k13); + K.ey.Set(k12, k22, k23); + K.ez.Set(k13, k23, k33); + + b2Vec3 C; + C.x = C1.x; + C.y = C1.y; + C.z = C2; + + impulse = K.Solve33(-C); + } + else + { + float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; + float32 k12 = iA * s1 + iB * s2; + float32 k22 = iA + iB; + if (k22 == 0.0f) + { + k22 = 1.0f; + } + + b2Mat22 K; + K.ex.Set(k11, k12); + K.ey.Set(k12, k22); + + b2Vec2 impulse1 = K.Solve(-C1); + impulse.x = impulse1.x; + impulse.y = impulse1.y; + impulse.z = 0.0f; + } + + b2Vec2 P = impulse.x * perp + impulse.z * axis; + float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; + float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; + + cA -= mA * P; + aA -= iA * LA; + cB += mB * P; + aB += iB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2PrismaticJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PrismaticJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); +} + +float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.y; +} + +float32 b2PrismaticJoint::GetJointTranslation() const +{ + b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2PrismaticJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); + b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); + b2Vec2 p1 = bA->m_sweep.c + rA; + b2Vec2 p2 = bB->m_sweep.c + rB; + b2Vec2 d = p2 - p1; + b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); + + b2Vec2 vA = bA->m_linearVelocity; + b2Vec2 vB = bB->m_linearVelocity; + float32 wA = bA->m_angularVelocity; + float32 wB = bB->m_angularVelocity; + + float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); + return speed; +} + +bool b2PrismaticJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2PrismaticJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2PrismaticJoint::GetLowerLimit() const +{ + return m_lowerTranslation; +} + +float32 b2PrismaticJoint::GetUpperLimit() const +{ + return m_upperTranslation; +} + +void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + if (lower != m_lowerTranslation || upper != m_upperTranslation) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_lowerTranslation = lower; + m_upperTranslation = upper; + m_impulse.z = 0.0f; + } +} + +bool b2PrismaticJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2PrismaticJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2PrismaticJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2PrismaticJoint::SetMaxMotorForce(float32 force) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorForce = force; +} + +float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2PrismaticJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PrismaticJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); + b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h new file mode 100644 index 0000000000..aca2859b45 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2PrismaticJoint.h @@ -0,0 +1,196 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_PRISMATIC_JOINT_H +#define B2_PRISMATIC_JOINT_H + +#include + +/// Prismatic joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct b2PrismaticJointDef : public b2JointDef +{ + b2PrismaticJointDef() + { + type = e_prismaticJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + referenceAngle = 0.0f; + enableLimit = false; + lowerTranslation = 0.0f; + upperTranslation = 0.0f; + enableMotor = false; + maxMotorForce = 0.0f; + motorSpeed = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and unit world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA. + b2Vec2 localAxisA; + + /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. + float32 referenceAngle; + + /// Enable/disable the joint limit. + bool enableLimit; + + /// The lower translation limit, usually in meters. + float32 lowerTranslation; + + /// The upper translation limit, usually in meters. + float32 upperTranslation; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorForce; + + /// The desired motor speed in radians per second. + float32 motorSpeed; +}; + +/// A prismatic joint. This joint provides one degree of freedom: translation +/// along an axis fixed in bodyA. Relative rotation is prevented. You can +/// use a joint limit to restrict the range of motion and a joint motor to +/// drive the motion or to model joint friction. +class b2PrismaticJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit, usually in meters. + float32 GetLowerLimit() const; + + /// Get the upper joint limit, usually in meters. + float32 GetUpperLimit() const; + + /// Set the joint limits, usually in meters. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in meters per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in meters per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor force, usually in N. + void SetMaxMotorForce(float32 force); + float32 GetMaxMotorForce() const { return m_maxMotorForce; } + + /// Get the current motor force given the inverse time step, usually in N. + float32 GetMotorForce(float32 inv_dt) const; + + /// Dump to b2Log + void Dump(); + +protected: + friend class b2Joint; + friend class b2GearJoint; + b2PrismaticJoint(const b2PrismaticJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + float32 m_referenceAngle; + b2Vec3 m_impulse; + float32 m_motorImpulse; + float32 m_lowerTranslation; + float32 m_upperTranslation; + float32 m_maxMotorForce; + float32 m_motorSpeed; + bool m_enableLimit; + bool m_enableMotor; + b2LimitState m_limitState; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Vec2 m_axis, m_perp; + float32 m_s1, m_s2; + float32 m_a1, m_a2; + b2Mat33 m_K; + float32 m_motorMass; +}; + +inline float32 b2PrismaticJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp new file mode 100644 index 0000000000..da30fae222 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2PulleyJoint.cpp @@ -0,0 +1,332 @@ +/* +* Copyright (c) 2007 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 +#include +#include + +// Pulley: +// length1 = norm(p1 - s1) +// length2 = norm(p2 - s2) +// C0 = (length1 + ratio * length2)_initial +// C = C0 - (length1 + ratio * length2) +// u1 = (p1 - s1) / norm(p1 - s1) +// u2 = (p2 - s2) / norm(p2 - s2) +// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) +// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] +// K = J * invM * JT +// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) + +void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, + const b2Vec2& groundA, const b2Vec2& groundB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 r) +{ + bodyA = bA; + bodyB = bB; + groundAnchorA = groundA; + groundAnchorB = groundB; + localAnchorA = bodyA->GetLocalPoint(anchorA); + localAnchorB = bodyB->GetLocalPoint(anchorB); + b2Vec2 dA = anchorA - groundA; + lengthA = dA.Length(); + b2Vec2 dB = anchorB - groundB; + lengthB = dB.Length(); + ratio = r; + b2Assert(ratio > b2_epsilon); +} + +b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) +: b2Joint(def) +{ + m_groundAnchorA = def->groundAnchorA; + m_groundAnchorB = def->groundAnchorB; + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_lengthA = def->lengthA; + m_lengthB = def->lengthB; + + b2Assert(def->ratio != 0.0f); + m_ratio = def->ratio; + + m_constant = def->lengthA + m_ratio * def->lengthB; + + m_impulse = 0.0f; +} + +void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + m_uA = cA + m_rA - m_groundAnchorA; + m_uB = cB + m_rB - m_groundAnchorB; + + float32 lengthA = m_uA.Length(); + float32 lengthB = m_uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + m_uA *= 1.0f / lengthA; + } + else + { + m_uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + m_uB *= 1.0f / lengthB; + } + else + { + m_uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(m_rA, m_uA); + float32 ruB = b2Cross(m_rB, m_uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + m_mass = mA + m_ratio * m_ratio * mB; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + + if (data.step.warmStarting) + { + // Scale impulses to support variable time steps. + m_impulse *= data.step.dtRatio; + + // Warm starting. + b2Vec2 PA = -(m_impulse) * m_uA; + b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; + + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + + float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 PA = -impulse * m_uA; + b2Vec2 PB = -m_ratio * impulse * m_uB; + vA += m_invMassA * PA; + wA += m_invIA * b2Cross(m_rA, PA); + vB += m_invMassB * PB; + wB += m_invIB * b2Cross(m_rB, PB); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // Get the pulley axes. + b2Vec2 uA = cA + rA - m_groundAnchorA; + b2Vec2 uB = cB + rB - m_groundAnchorB; + + float32 lengthA = uA.Length(); + float32 lengthB = uB.Length(); + + if (lengthA > 10.0f * b2_linearSlop) + { + uA *= 1.0f / lengthA; + } + else + { + uA.SetZero(); + } + + if (lengthB > 10.0f * b2_linearSlop) + { + uB *= 1.0f / lengthB; + } + else + { + uB.SetZero(); + } + + // Compute effective mass. + float32 ruA = b2Cross(rA, uA); + float32 ruB = b2Cross(rB, uB); + + float32 mA = m_invMassA + m_invIA * ruA * ruA; + float32 mB = m_invMassB + m_invIB * ruB * ruB; + + float32 mass = mA + m_ratio * m_ratio * mB; + + if (mass > 0.0f) + { + mass = 1.0f / mass; + } + + float32 C = m_constant - lengthA - m_ratio * lengthB; + float32 linearError = b2Abs(C); + + float32 impulse = -mass * C; + + b2Vec2 PA = -impulse * uA; + b2Vec2 PB = -m_ratio * impulse * uB; + + cA += m_invMassA * PA; + aA += m_invIA * b2Cross(rA, PA); + cB += m_invMassB * PB; + aB += m_invIB * b2Cross(rB, PB); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return linearError < b2_linearSlop; +} + +b2Vec2 b2PulleyJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2PulleyJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P = m_impulse * m_uB; + return inv_dt * P; +} + +float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorA() const +{ + return m_groundAnchorA; +} + +b2Vec2 b2PulleyJoint::GetGroundAnchorB() const +{ + return m_groundAnchorB; +} + +float32 b2PulleyJoint::GetLengthA() const +{ + b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); + b2Vec2 s = m_groundAnchorA; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetLengthB() const +{ + b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); + b2Vec2 s = m_groundAnchorB; + b2Vec2 d = p - s; + return d.Length(); +} + +float32 b2PulleyJoint::GetRatio() const +{ + return m_ratio; +} + +void b2PulleyJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2PulleyJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); + b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); + b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); + b2Log(" jd.ratio = %.15lef;\n", m_ratio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2PulleyJoint.h b/external/Box2D/Dynamics/Joints/b2PulleyJoint.h new file mode 100644 index 0000000000..2f6df4395c --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2PulleyJoint.h @@ -0,0 +1,143 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_PULLEY_JOINT_H +#define B2_PULLEY_JOINT_H + +#include + +const float32 b2_minPulleyLength = 2.0f; + +/// Pulley joint definition. This requires two ground anchors, +/// two dynamic body anchor points, and a pulley ratio. +struct b2PulleyJointDef : public b2JointDef +{ + b2PulleyJointDef() + { + type = e_pulleyJoint; + groundAnchorA.Set(-1.0f, 1.0f); + groundAnchorB.Set(1.0f, 1.0f); + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + lengthA = 0.0f; + lengthB = 0.0f; + ratio = 1.0f; + collideConnected = true; + } + + /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 ratio); + + /// The first ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorA; + + /// The second ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorB; + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The a reference length for the segment attached to bodyA. + float32 lengthA; + + /// The a reference length for the segment attached to bodyB. + float32 lengthB; + + /// The pulley ratio, used to simulate a block-and-tackle. + float32 ratio; +}; + +/// The pulley joint is connected to two bodies and two fixed ground points. +/// The pulley supports a ratio such that: +/// length1 + ratio * length2 <= constant +/// Yes, the force transmitted is scaled by the ratio. +/// Warning: the pulley joint can get a bit squirrelly by itself. They often +/// work better when combined with prismatic joints. You should also cover the +/// the anchor points with static shapes to prevent one side from going to +/// zero length. +class b2PulleyJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first ground anchor. + b2Vec2 GetGroundAnchorA() const; + + /// Get the second ground anchor. + b2Vec2 GetGroundAnchorB() const; + + /// Get the current length of the segment attached to bodyA. + float32 GetLengthA() const; + + /// Get the current length of the segment attached to bodyB. + float32 GetLengthB() const; + + /// Get the pulley ratio. + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2PulleyJoint(const b2PulleyJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_groundAnchorA; + b2Vec2 m_groundAnchorB; + float32 m_lengthA; + float32 m_lengthB; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_constant; + float32 m_ratio; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_uA; + b2Vec2 m_uB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp new file mode 100644 index 0000000000..e265d8192b --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp @@ -0,0 +1,504 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Motor constraint +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + + m_lowerAngle = def->lowerAngle; + m_upperAngle = def->upperAngle; + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableLimit = def->enableLimit; + m_enableMotor = def->enableMotor; + m_limitState = e_inactiveLimit; +} + +void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; + m_mass.ex.y = m_mass.ey.x; + m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; + m_mass.ex.z = m_mass.ez.x; + m_mass.ey.z = m_mass.ez.y; + m_mass.ez.z = iA + iB; + + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + + if (m_enableMotor == false || fixedRotation) + { + m_motorImpulse = 0.0f; + } + + if (m_enableLimit && fixedRotation == false) + { + float32 jointAngle = aB - aA - m_referenceAngle; + if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) + { + m_limitState = e_equalLimits; + } + else if (jointAngle <= m_lowerAngle) + { + if (m_limitState != e_atLowerLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atLowerLimit; + } + else if (jointAngle >= m_upperAngle) + { + if (m_limitState != e_atUpperLimit) + { + m_impulse.z = 0.0f; + } + m_limitState = e_atUpperLimit; + } + else + { + m_limitState = e_inactiveLimit; + m_impulse.z = 0.0f; + } + } + else + { + m_limitState = e_inactiveLimit; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); + } + else + { + m_impulse.SetZero(); + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + bool fixedRotation = (iA + iB == 0.0f); + + // Solve motor constraint. + if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -m_mass.Solve33(Cdot); + + if (m_limitState == e_equalLimits) + { + m_impulse += impulse; + } + else if (m_limitState == e_atLowerLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse < 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + else if (m_limitState == e_atUpperLimit) + { + float32 newImpulse = m_impulse.z + impulse.z; + if (newImpulse > 0.0f) + { + b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); + b2Vec2 reduced = m_mass.Solve22(rhs); + impulse.x = reduced.x; + impulse.y = reduced.y; + impulse.z = -m_impulse.z; + m_impulse.x += reduced.x; + m_impulse.y += reduced.y; + m_impulse.z = 0.0f; + } + else + { + m_impulse += impulse; + } + } + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + else + { + // Solve point-to-point constraint + b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + b2Vec2 impulse = m_mass.Solve22(-Cdot); + + m_impulse.x += impulse.x; + m_impulse.y += impulse.y; + + vA -= mA * impulse; + wA -= iA * b2Cross(m_rA, impulse); + + vB += mB * impulse; + wB += iB * b2Cross(m_rB, impulse); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 angularError = 0.0f; + float32 positionError = 0.0f; + + bool fixedRotation = (m_invIA + m_invIB == 0.0f); + + // Solve angular limit constraint. + if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) + { + float32 angle = aB - aA - m_referenceAngle; + float32 limitImpulse = 0.0f; + + if (m_limitState == e_equalLimits) + { + // Prevent large angular corrections + float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + angularError = b2Abs(C); + } + else if (m_limitState == e_atLowerLimit) + { + float32 C = angle - m_lowerAngle; + angularError = -C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); + limitImpulse = -m_motorMass * C; + } + else if (m_limitState == e_atUpperLimit) + { + float32 C = angle - m_upperAngle; + angularError = C; + + // Prevent large angular corrections and allow some slop. + C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); + limitImpulse = -m_motorMass * C; + } + + aA -= m_invIA * limitImpulse; + aB += m_invIB * limitImpulse; + } + + // Solve point-to-point constraint. + { + qA.Set(aA); + qB.Set(aB); + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + b2Vec2 C = cB + rB - cA - rA; + positionError = C.Length(); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat22 K; + K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; + K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; + K.ey.x = K.ex.y; + K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; + + b2Vec2 impulse = -K.Solve(C); + + cA -= mA * impulse; + aA -= iA * b2Cross(rA, impulse); + + cB += mB * impulse; + aB += iB * b2Cross(rB, impulse); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2RevoluteJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RevoluteJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +float32 b2RevoluteJoint::GetJointAngle() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; +} + +float32 b2RevoluteJoint::GetJointSpeed() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + return bB->m_angularVelocity - bA->m_angularVelocity; +} + +bool b2RevoluteJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2RevoluteJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2RevoluteJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +bool b2RevoluteJoint::IsLimitEnabled() const +{ + return m_enableLimit; +} + +void b2RevoluteJoint::EnableLimit(bool flag) +{ + if (flag != m_enableLimit) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableLimit = flag; + m_impulse.z = 0.0f; + } +} + +float32 b2RevoluteJoint::GetLowerLimit() const +{ + return m_lowerAngle; +} + +float32 b2RevoluteJoint::GetUpperLimit() const +{ + return m_upperAngle; +} + +void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) +{ + b2Assert(lower <= upper); + + if (lower != m_lowerAngle || upper != m_upperAngle) + { + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_impulse.z = 0.0f; + m_lowerAngle = lower; + m_upperAngle = upper; + } +} + +void b2RevoluteJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RevoluteJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); + b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); + b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h new file mode 100644 index 0000000000..978f16259a --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2RevoluteJoint.h @@ -0,0 +1,204 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_REVOLUTE_JOINT_H +#define B2_REVOLUTE_JOINT_H + +#include + +/// Revolute joint definition. This requires defining an +/// anchor point where the bodies are joined. The definition +/// uses local anchor points so that the initial configuration +/// can violate the constraint slightly. You also need to +/// specify the initial relative angle for joint limits. This +/// helps when saving and loading a game. +/// The local anchor points are measured from the body's origin +/// rather than the center of mass because: +/// 1. you might not know where the center of mass will be. +/// 2. if you add/remove shapes from a body and recompute the mass, +/// the joints will be broken. +struct b2RevoluteJointDef : public b2JointDef +{ + b2RevoluteJointDef() + { + type = e_revoluteJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + lowerAngle = 0.0f; + upperAngle = 0.0f; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + enableLimit = false; + enableMotor = false; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// A flag to enable joint limits. + bool enableLimit; + + /// The lower angle for the joint limit (radians). + float32 lowerAngle; + + /// The upper angle for the joint limit (radians). + float32 upperAngle; + + /// A flag to enable the joint motor. + bool enableMotor; + + /// The desired motor speed. Usually in radians per second. + float32 motorSpeed; + + /// The maximum motor torque used to achieve the desired motor speed. + /// Usually in N-m. + float32 maxMotorTorque; +}; + +/// A revolute joint constrains two bodies to share a common point while they +/// are free to rotate about the point. The relative rotation about the shared +/// point is the joint angle. You can limit the relative rotation with +/// a joint limit that specifies a lower and upper angle. You can use a motor +/// to drive the relative rotation about the shared point. A maximum motor torque +/// is provided so that infinite forces are not generated. +class b2RevoluteJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint angle in radians. + float32 GetJointAngle() const; + + /// Get the current joint angle speed in radians per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit in radians. + float32 GetLowerLimit() const; + + /// Get the upper joint limit in radians. + float32 GetUpperLimit() const; + + /// Set the joint limits in radians. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed in radians per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor torque, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque due to the joint limit given the inverse time step. + /// Unit is N*m. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the current motor torque given the inverse time step. + /// Unit is N*m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Dump to b2Log. + void Dump(); + +protected: + + friend class b2Joint; + friend class b2GearJoint; + + b2RevoluteJoint(const b2RevoluteJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec3 m_impulse; + float32 m_motorImpulse; + + bool m_enableMotor; + float32 m_maxMotorTorque; + float32 m_motorSpeed; + + bool m_enableLimit; + float32 m_referenceAngle; + float32 m_lowerAngle; + float32 m_upperAngle; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; // effective mass for point-to-point constraint. + float32 m_motorMass; // effective mass for motor/limit angular constraint. + b2LimitState m_limitState; +}; + +inline float32 b2RevoluteJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp new file mode 100644 index 0000000000..17a70d9230 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2RopeJoint.cpp @@ -0,0 +1,241 @@ +/* +* Copyright (c) 2007-2011 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 +#include +#include + + +// Limit: +// C = norm(pB - pA) - L +// u = (pB - pA) / norm(pB - pA) +// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) +// J = [-u -cross(rA, u) u cross(rB, u)] +// K = J * invM * JT +// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 + +b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + + m_maxLength = def->maxLength; + + m_mass = 0.0f; + m_impulse = 0.0f; + m_state = e_inactiveLimit; + m_length = 0.0f; +} + +void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + m_u = cB + m_rB - cA - m_rA; + + m_length = m_u.Length(); + + float32 C = m_length - m_maxLength; + if (C > 0.0f) + { + m_state = e_atUpperLimit; + } + else + { + m_state = e_inactiveLimit; + } + + if (m_length > b2_linearSlop) + { + m_u *= 1.0f / m_length; + } + else + { + m_u.SetZero(); + m_mass = 0.0f; + m_impulse = 0.0f; + return; + } + + // Compute effective mass. + float32 crA = b2Cross(m_rA, m_u); + float32 crB = b2Cross(m_rB, m_u); + float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; + + m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; + + if (data.step.warmStarting) + { + // Scale the impulse to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + } + else + { + m_impulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Cdot = dot(u, v + cross(w, r)) + b2Vec2 vpA = vA + b2Cross(wA, m_rA); + b2Vec2 vpB = vB + b2Cross(wB, m_rB); + float32 C = m_length - m_maxLength; + float32 Cdot = b2Dot(m_u, vpB - vpA); + + // Predictive constraint. + if (C < 0.0f) + { + Cdot += data.step.inv_dt * C; + } + + float32 impulse = -m_mass * Cdot; + float32 oldImpulse = m_impulse; + m_impulse = b2Min(0.0f, m_impulse + impulse); + impulse = m_impulse - oldImpulse; + + b2Vec2 P = impulse * m_u; + vA -= m_invMassA * P; + wA -= m_invIA * b2Cross(m_rA, P); + vB += m_invMassB * P; + wB += m_invIB * b2Cross(m_rB, P); + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 u = cB + rB - cA - rA; + + float32 length = u.Normalize(); + float32 C = length - m_maxLength; + + C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); + + float32 impulse = -m_mass * C; + b2Vec2 P = impulse * u; + + cA -= m_invMassA * P; + aA -= m_invIA * b2Cross(rA, P); + cB += m_invMassB * P; + aB += m_invIB * b2Cross(rB, P); + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return length - m_maxLength < b2_linearSlop; +} + +b2Vec2 b2RopeJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2RopeJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 F = (inv_dt * m_impulse) * m_u; + return F; +} + +float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const +{ + B2_NOT_USED(inv_dt); + return 0.0f; +} + +float32 b2RopeJoint::GetMaxLength() const +{ + return m_maxLength; +} + +b2LimitState b2RopeJoint::GetLimitState() const +{ + return m_state; +} + +void b2RopeJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2RopeJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2RopeJoint.h b/external/Box2D/Dynamics/Joints/b2RopeJoint.h new file mode 100644 index 0000000000..d7091b6650 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2RopeJoint.h @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_ROPE_JOINT_H +#define B2_ROPE_JOINT_H + +#include + +/// Rope joint definition. This requires two body anchor points and +/// a maximum lengths. +/// Note: by default the connected objects will not collide. +/// see collideConnected in b2JointDef. +struct b2RopeJointDef : public b2JointDef +{ + b2RopeJointDef() + { + type = e_ropeJoint; + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + maxLength = 0.0f; + } + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum length of the rope. + /// Warning: this must be larger than b2_linearSlop or + /// the joint will have no effect. + float32 maxLength; +}; + +/// A rope joint enforces a maximum distance between two points +/// on two bodies. It has no other effect. +/// Warning: if you attempt to change the maximum length during +/// the simulation you will get some non-physical behavior. +/// A model that would allow you to dynamically modify the length +/// would have some sponginess, so I chose not to implement it +/// that way. See b2DistanceJoint if you want to dynamically +/// control length. +class b2RopeJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/Get the maximum length of the rope. + void SetMaxLength(float32 length) { m_maxLength = length; } + float32 GetMaxLength() const; + + b2LimitState GetLimitState() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2RopeJoint(const b2RopeJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_maxLength; + float32 m_length; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; + b2LimitState m_state; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp new file mode 100644 index 0000000000..f50bdd6587 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2WeldJoint.cpp @@ -0,0 +1,330 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include + +// Point-to-point constraint +// C = p2 - p1 +// Cdot = v2 - v1 +// = v2 + cross(w2, r2) - v1 - cross(w1, r1) +// J = [-I -r1_skew I r2_skew ] +// Identity used: +// w k % (rx i + ry j) = w * (-ry i + rx j) + +// Angle constraint +// C = angle2 - angle1 - referenceAngle +// Cdot = w2 - w1 +// J = [0 0 -1 0 0 1] +// K = invI1 + invI2 + +void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); +} + +b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_referenceAngle = def->referenceAngle; + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_impulse.SetZero(); +} + +void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + // J = [-I -r1_skew I r2_skew] + // [ 0 -1 0 1] + // r_skew = [-ry; rx] + + // Matlab + // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] + // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] + // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Mat33 K; + K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; + K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; + K.ez.x = -m_rA.y * iA - m_rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; + K.ez.y = m_rA.x * iA + m_rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + K.GetInverse22(&m_mass); + + float32 invM = iA + iB; + float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; + + float32 C = aB - aA - m_referenceAngle; + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; + m_bias = C * h * k * m_gamma; + + invM += m_gamma; + m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; + } + else + { + K.GetSymInverse33(&m_mass); + m_gamma = 0.0f; + m_bias = 0.0f; + } + + if (data.step.warmStarting) + { + // Scale impulses to support a variable time step. + m_impulse *= data.step.dtRatio; + + b2Vec2 P(m_impulse.x, m_impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + m_impulse.z); + } + else + { + m_impulse.SetZero(); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + if (m_frequencyHz > 0.0f) + { + float32 Cdot2 = wB - wA; + + float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); + m_impulse.z += impulse2; + + wA -= iA * impulse2; + wB += iB * impulse2; + + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + + b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); + m_impulse.x += impulse1.x; + m_impulse.y += impulse1.y; + + b2Vec2 P = impulse1; + + vA -= mA * P; + wA -= iA * b2Cross(m_rA, P); + + vB += mB * P; + wB += iB * b2Cross(m_rB, P); + } + else + { + b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); + float32 Cdot2 = wB - wA; + b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); + + b2Vec3 impulse = -b2Mul(m_mass, Cdot); + m_impulse += impulse; + + b2Vec2 P(impulse.x, impulse.y); + + vA -= mA * P; + wA -= iA * (b2Cross(m_rA, P) + impulse.z); + + vB += mB * P; + wB += iB * (b2Cross(m_rB, P) + impulse.z); + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + + float32 positionError, angularError; + + b2Mat33 K; + K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; + K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; + K.ez.x = -rA.y * iA - rB.y * iB; + K.ex.y = K.ey.x; + K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; + K.ez.y = rA.x * iA + rB.x * iB; + K.ex.z = K.ez.x; + K.ey.z = K.ez.y; + K.ez.z = iA + iB; + + if (m_frequencyHz > 0.0f) + { + b2Vec2 C1 = cB + rB - cA - rA; + + positionError = C1.Length(); + angularError = 0.0f; + + b2Vec2 P = -K.Solve22(C1); + + cA -= mA * P; + aA -= iA * b2Cross(rA, P); + + cB += mB * P; + aB += iB * b2Cross(rB, P); + } + else + { + b2Vec2 C1 = cB + rB - cA - rA; + float32 C2 = aB - aA - m_referenceAngle; + + positionError = C1.Length(); + angularError = b2Abs(C2); + + b2Vec3 C(C1.x, C1.y, C2); + + b2Vec3 impulse = -K.Solve33(C); + b2Vec2 P(impulse.x, impulse.y); + + cA -= mA * P; + aA -= iA * (b2Cross(rA, P) + impulse.z); + + cB += mB * P; + aB += iB * (b2Cross(rB, P) + impulse.z); + } + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return positionError <= b2_linearSlop && angularError <= b2_angularSlop; +} + +b2Vec2 b2WeldJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WeldJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const +{ + b2Vec2 P(m_impulse.x, m_impulse.y); + return inv_dt * P; +} + +float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_impulse.z; +} + +void b2WeldJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WeldJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2WeldJoint.h b/external/Box2D/Dynamics/Joints/b2WeldJoint.h new file mode 100644 index 0000000000..751c6a8770 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2WeldJoint.h @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WELD_JOINT_H +#define B2_WELD_JOINT_H + +#include + +/// Weld joint definition. You need to specify local anchor points +/// where they are attached and the relative body angle. The position +/// of the anchor points is important for computing the reaction torque. +struct b2WeldJointDef : public b2JointDef +{ + b2WeldJointDef() + { + type = e_weldJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// The mass-spring-damper frequency in Hertz. Rotation only. + /// Disable softness with a value of 0. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A weld joint essentially glues two bodies together. A weld joint may +/// distort somewhat because the island constraint solver is approximate. +class b2WeldJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz) { m_frequencyHz = hz; } + float32 GetFrequency() const { return m_frequencyHz; } + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } + float32 GetDampingRatio() const { return m_dampingRatio; } + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + + b2WeldJoint(const b2WeldJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_referenceAngle; + float32 m_gamma; + b2Vec3 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; +}; + +#endif diff --git a/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp new file mode 100644 index 0000000000..6253437706 --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2WheelJoint.cpp @@ -0,0 +1,419 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include + +// Linear constraint (point-to-line) +// d = pB - pA = xB + rB - xA - rA +// C = dot(ay, d) +// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) +// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) +// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] + +// Spring linear constraint +// C = dot(ax, d) +// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) +// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] + +// Motor rotational constraint +// Cdot = wB - wA +// J = [0 0 -1 0 0 1] + +void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) +{ + bodyA = bA; + bodyB = bB; + localAnchorA = bodyA->GetLocalPoint(anchor); + localAnchorB = bodyB->GetLocalPoint(anchor); + localAxisA = bodyA->GetLocalVector(axis); +} + +b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) +: b2Joint(def) +{ + m_localAnchorA = def->localAnchorA; + m_localAnchorB = def->localAnchorB; + m_localXAxisA = def->localAxisA; + m_localYAxisA = b2Cross(1.0f, m_localXAxisA); + + m_mass = 0.0f; + m_impulse = 0.0f; + m_motorMass = 0.0; + m_motorImpulse = 0.0f; + m_springMass = 0.0f; + m_springImpulse = 0.0f; + + m_maxMotorTorque = def->maxMotorTorque; + m_motorSpeed = def->motorSpeed; + m_enableMotor = def->enableMotor; + + m_frequencyHz = def->frequencyHz; + m_dampingRatio = def->dampingRatio; + + m_bias = 0.0f; + m_gamma = 0.0f; + + m_ax.SetZero(); + m_ay.SetZero(); +} + +void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) +{ + m_indexA = m_bodyA->m_islandIndex; + m_indexB = m_bodyB->m_islandIndex; + m_localCenterA = m_bodyA->m_sweep.localCenter; + m_localCenterB = m_bodyB->m_sweep.localCenter; + m_invMassA = m_bodyA->m_invMass; + m_invMassB = m_bodyB->m_invMass; + m_invIA = m_bodyA->m_invI; + m_invIB = m_bodyB->m_invI; + + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + b2Rot qA(aA), qB(aB); + + // Compute the effective masses. + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = cB + rB - cA - rA; + + // Point to line constraint + { + m_ay = b2Mul(qA, m_localYAxisA); + m_sAy = b2Cross(d + rA, m_ay); + m_sBy = b2Cross(rB, m_ay); + + m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; + + if (m_mass > 0.0f) + { + m_mass = 1.0f / m_mass; + } + } + + // Spring constraint + m_springMass = 0.0f; + m_bias = 0.0f; + m_gamma = 0.0f; + if (m_frequencyHz > 0.0f) + { + m_ax = b2Mul(qA, m_localXAxisA); + m_sAx = b2Cross(d + rA, m_ax); + m_sBx = b2Cross(rB, m_ax); + + float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; + + if (invMass > 0.0f) + { + m_springMass = 1.0f / invMass; + + float32 C = b2Dot(d, m_ax); + + // Frequency + float32 omega = 2.0f * b2_pi * m_frequencyHz; + + // Damping coefficient + float32 d = 2.0f * m_springMass * m_dampingRatio * omega; + + // Spring stiffness + float32 k = m_springMass * omega * omega; + + // magic formulas + float32 h = data.step.dt; + m_gamma = h * (d + h * k); + if (m_gamma > 0.0f) + { + m_gamma = 1.0f / m_gamma; + } + + m_bias = C * h * k * m_gamma; + + m_springMass = invMass + m_gamma; + if (m_springMass > 0.0f) + { + m_springMass = 1.0f / m_springMass; + } + } + } + else + { + m_springImpulse = 0.0f; + } + + // Rotational motor + if (m_enableMotor) + { + m_motorMass = iA + iB; + if (m_motorMass > 0.0f) + { + m_motorMass = 1.0f / m_motorMass; + } + } + else + { + m_motorMass = 0.0f; + m_motorImpulse = 0.0f; + } + + if (data.step.warmStarting) + { + // Account for variable time step. + m_impulse *= data.step.dtRatio; + m_springImpulse *= data.step.dtRatio; + m_motorImpulse *= data.step.dtRatio; + + b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; + float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; + float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; + + vA -= m_invMassA * P; + wA -= m_invIA * LA; + + vB += m_invMassB * P; + wB += m_invIB * LB; + } + else + { + m_impulse = 0.0f; + m_springImpulse = 0.0f; + m_motorImpulse = 0.0f; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) +{ + float32 mA = m_invMassA, mB = m_invMassB; + float32 iA = m_invIA, iB = m_invIB; + + b2Vec2 vA = data.velocities[m_indexA].v; + float32 wA = data.velocities[m_indexA].w; + b2Vec2 vB = data.velocities[m_indexB].v; + float32 wB = data.velocities[m_indexB].w; + + // Solve spring constraint + { + float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; + float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); + m_springImpulse += impulse; + + b2Vec2 P = impulse * m_ax; + float32 LA = impulse * m_sAx; + float32 LB = impulse * m_sBx; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + // Solve rotational motor constraint + { + float32 Cdot = wB - wA - m_motorSpeed; + float32 impulse = -m_motorMass * Cdot; + + float32 oldImpulse = m_motorImpulse; + float32 maxImpulse = data.step.dt * m_maxMotorTorque; + m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = m_motorImpulse - oldImpulse; + + wA -= iA * impulse; + wB += iB * impulse; + } + + // Solve point to line constraint + { + float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; + float32 impulse = -m_mass * Cdot; + m_impulse += impulse; + + b2Vec2 P = impulse * m_ay; + float32 LA = impulse * m_sAy; + float32 LB = impulse * m_sBy; + + vA -= mA * P; + wA -= iA * LA; + + vB += mB * P; + wB += iB * LB; + } + + data.velocities[m_indexA].v = vA; + data.velocities[m_indexA].w = wA; + data.velocities[m_indexB].v = vB; + data.velocities[m_indexB].w = wB; +} + +bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) +{ + b2Vec2 cA = data.positions[m_indexA].c; + float32 aA = data.positions[m_indexA].a; + b2Vec2 cB = data.positions[m_indexB].c; + float32 aB = data.positions[m_indexB].a; + + b2Rot qA(aA), qB(aB); + + b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); + b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); + b2Vec2 d = (cB - cA) + rB - rA; + + b2Vec2 ay = b2Mul(qA, m_localYAxisA); + + float32 sAy = b2Cross(d + rA, ay); + float32 sBy = b2Cross(rB, ay); + + float32 C = b2Dot(d, ay); + + float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; + + float32 impulse; + if (k != 0.0f) + { + impulse = - C / k; + } + else + { + impulse = 0.0f; + } + + b2Vec2 P = impulse * ay; + float32 LA = impulse * sAy; + float32 LB = impulse * sBy; + + cA -= m_invMassA * P; + aA -= m_invIA * LA; + cB += m_invMassB * P; + aB += m_invIB * LB; + + data.positions[m_indexA].c = cA; + data.positions[m_indexA].a = aA; + data.positions[m_indexB].c = cB; + data.positions[m_indexB].a = aB; + + return b2Abs(C) <= b2_linearSlop; +} + +b2Vec2 b2WheelJoint::GetAnchorA() const +{ + return m_bodyA->GetWorldPoint(m_localAnchorA); +} + +b2Vec2 b2WheelJoint::GetAnchorB() const +{ + return m_bodyB->GetWorldPoint(m_localAnchorB); +} + +b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const +{ + return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); +} + +float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +float32 b2WheelJoint::GetJointTranslation() const +{ + b2Body* bA = m_bodyA; + b2Body* bB = m_bodyB; + + b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); + b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); + b2Vec2 d = pB - pA; + b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); + + float32 translation = b2Dot(d, axis); + return translation; +} + +float32 b2WheelJoint::GetJointSpeed() const +{ + float32 wA = m_bodyA->m_angularVelocity; + float32 wB = m_bodyB->m_angularVelocity; + return wB - wA; +} + +bool b2WheelJoint::IsMotorEnabled() const +{ + return m_enableMotor; +} + +void b2WheelJoint::EnableMotor(bool flag) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_enableMotor = flag; +} + +void b2WheelJoint::SetMotorSpeed(float32 speed) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_motorSpeed = speed; +} + +void b2WheelJoint::SetMaxMotorTorque(float32 torque) +{ + m_bodyA->SetAwake(true); + m_bodyB->SetAwake(true); + m_maxMotorTorque = torque; +} + +float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const +{ + return inv_dt * m_motorImpulse; +} + +void b2WheelJoint::Dump() +{ + int32 indexA = m_bodyA->m_islandIndex; + int32 indexB = m_bodyB->m_islandIndex; + + b2Log(" b2WheelJointDef jd;\n"); + b2Log(" jd.bodyA = bodies[%d];\n", indexA); + b2Log(" jd.bodyB = bodies[%d];\n", indexB); + b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); + b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); + b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); + b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); + b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); + b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); + b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); + b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); + b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); + b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); +} diff --git a/external/Box2D/Dynamics/Joints/b2WheelJoint.h b/external/Box2D/Dynamics/Joints/b2WheelJoint.h new file mode 100644 index 0000000000..ede1b08b7c --- /dev/null +++ b/external/Box2D/Dynamics/Joints/b2WheelJoint.h @@ -0,0 +1,213 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WHEEL_JOINT_H +#define B2_WHEEL_JOINT_H + +#include + +/// Wheel joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct b2WheelJointDef : public b2JointDef +{ + b2WheelJointDef() + { + type = e_wheelJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + enableMotor = false; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + frequencyHz = 2.0f; + dampingRatio = 0.7f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation axis in bodyA. + b2Vec2 localAxisA; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorTorque; + + /// The desired motor speed in radians per second. + float32 motorSpeed; + + /// Suspension frequency, zero indicates no suspension + float32 frequencyHz; + + /// Suspension damping ratio, one indicates critical damping + float32 dampingRatio; +}; + +/// A wheel joint. This joint provides two degrees of freedom: translation +/// along an axis fixed in bodyA and rotation in the plane. You can use a +/// joint limit to restrict the range of motion and a joint motor to drive +/// the rotation or to model rotational friction. +/// This joint is designed for vehicle suspensions. +class b2WheelJoint : public b2Joint +{ +public: + void GetDefinition(b2WheelJointDef* def) const; + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in radians per second. + float32 GetMotorSpeed() const; + + /// Set/Get the maximum motor force, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const; + + /// Get the current motor torque given the inverse time step, usually in N-m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. + void SetSpringFrequencyHz(float32 hz); + float32 GetSpringFrequencyHz() const; + + /// Set/Get the spring damping ratio + void SetSpringDampingRatio(float32 ratio); + float32 GetSpringDampingRatio() const; + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + b2WheelJoint(const b2WheelJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + + float32 m_impulse; + float32 m_motorImpulse; + float32 m_springImpulse; + + float32 m_maxMotorTorque; + float32 m_motorSpeed; + bool m_enableMotor; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + + b2Vec2 m_ax, m_ay; + float32 m_sAx, m_sBx; + float32 m_sAy, m_sBy; + + float32 m_mass; + float32 m_motorMass; + float32 m_springMass; + + float32 m_bias; + float32 m_gamma; +}; + +inline float32 b2WheelJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +inline float32 b2WheelJoint::GetMaxMotorTorque() const +{ + return m_maxMotorTorque; +} + +inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2WheelJoint::GetSpringFrequencyHz() const +{ + return m_frequencyHz; +} + +inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2WheelJoint::GetSpringDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/external/Box2D/Dynamics/b2Body.cpp b/external/Box2D/Dynamics/b2Body.cpp new file mode 100644 index 0000000000..b22b574023 --- /dev/null +++ b/external/Box2D/Dynamics/b2Body.cpp @@ -0,0 +1,514 @@ +/* +* Copyright (c) 2006-2007 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 +#include +#include +#include +#include + +b2Body::b2Body(const b2BodyDef* bd, b2World* world) +{ + b2Assert(bd->position.IsValid()); + b2Assert(bd->linearVelocity.IsValid()); + b2Assert(b2IsValid(bd->angle)); + b2Assert(b2IsValid(bd->angularVelocity)); + b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); + b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); + + m_flags = 0; + + if (bd->bullet) + { + m_flags |= e_bulletFlag; + } + if (bd->fixedRotation) + { + m_flags |= e_fixedRotationFlag; + } + if (bd->allowSleep) + { + m_flags |= e_autoSleepFlag; + } + if (bd->awake) + { + m_flags |= e_awakeFlag; + } + if (bd->active) + { + m_flags |= e_activeFlag; + } + + m_world = world; + + m_xf.p = bd->position; + m_xf.q.Set(bd->angle); + + m_sweep.localCenter.SetZero(); + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = bd->angle; + m_sweep.a = bd->angle; + m_sweep.alpha0 = 0.0f; + + m_jointList = NULL; + m_contactList = NULL; + m_prev = NULL; + m_next = NULL; + + m_linearVelocity = bd->linearVelocity; + m_angularVelocity = bd->angularVelocity; + + m_linearDamping = bd->linearDamping; + m_angularDamping = bd->angularDamping; + m_gravityScale = bd->gravityScale; + + m_force.SetZero(); + m_torque = 0.0f; + + m_sleepTime = 0.0f; + + m_type = bd->type; + + if (m_type == b2_dynamicBody) + { + m_mass = 1.0f; + m_invMass = 1.0f; + } + else + { + m_mass = 0.0f; + m_invMass = 0.0f; + } + + m_I = 0.0f; + m_invI = 0.0f; + + m_userData = bd->userData; + + m_fixtureList = NULL; + m_fixtureCount = 0; +} + +b2Body::~b2Body() +{ + // shapes and joints are destroyed in b2World::Destroy +} + +void b2Body::SetType(b2BodyType type) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type == type) + { + return; + } + + m_type = type; + + ResetMassData(); + + if (m_type == b2_staticBody) + { + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_sweep.a0 = m_sweep.a; + m_sweep.c0 = m_sweep.c; + SynchronizeFixtures(); + } + + SetAwake(true); + + m_force.SetZero(); + m_torque = 0.0f; + + // Since the body type changed, we need to flag contacts for filtering. + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Refilter(); + } +} + +b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return NULL; + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + void* memory = allocator->Allocate(sizeof(b2Fixture)); + b2Fixture* fixture = new (memory) b2Fixture; + fixture->Create(allocator, this, def); + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->CreateProxies(broadPhase, m_xf); + } + + fixture->m_next = m_fixtureList; + m_fixtureList = fixture; + ++m_fixtureCount; + + fixture->m_body = this; + + // Adjust mass properties if needed. + if (fixture->m_density > 0.0f) + { + ResetMassData(); + } + + // Let the world know we have a new fixture. This will cause new contacts + // to be created at the beginning of the next time step. + m_world->m_flags |= b2World::e_newFixture; + + return fixture; +} + +b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) +{ + b2FixtureDef def; + def.shape = shape; + def.density = density; + + return CreateFixture(&def); +} + +void b2Body::DestroyFixture(b2Fixture* fixture) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + b2Assert(fixture->m_body == this); + + // Remove the fixture from this body's singly linked list. + b2Assert(m_fixtureCount > 0); + b2Fixture** node = &m_fixtureList; + bool found = false; + while (*node != NULL) + { + if (*node == fixture) + { + *node = fixture->m_next; + found = true; + break; + } + + node = &(*node)->m_next; + } + + // You tried to remove a shape that is not attached to this body. + b2Assert(found); + + // Destroy any contacts associated with the fixture. + b2ContactEdge* edge = m_contactList; + while (edge) + { + b2Contact* c = edge->contact; + edge = edge->next; + + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + + if (fixture == fixtureA || fixture == fixtureB) + { + // This destroys the contact and removes it from + // this body's contact list. + m_world->m_contactManager.Destroy(c); + } + } + + b2BlockAllocator* allocator = &m_world->m_blockAllocator; + + if (m_flags & e_activeFlag) + { + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + fixture->DestroyProxies(broadPhase); + } + + fixture->Destroy(allocator); + fixture->m_body = NULL; + fixture->m_next = NULL; + fixture->~b2Fixture(); + allocator->Free(fixture, sizeof(b2Fixture)); + + --m_fixtureCount; + + // Reset the mass data. + ResetMassData(); +} + +void b2Body::ResetMassData() +{ + // Compute mass data from shapes. Each shape has its own density. + m_mass = 0.0f; + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + m_sweep.localCenter.SetZero(); + + // Static and kinematic bodies have zero mass. + if (m_type == b2_staticBody || m_type == b2_kinematicBody) + { + m_sweep.c0 = m_xf.p; + m_sweep.c = m_xf.p; + m_sweep.a0 = m_sweep.a; + return; + } + + b2Assert(m_type == b2_dynamicBody); + + // Accumulate mass over all fixtures. + b2Vec2 localCenter = b2Vec2_zero; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + if (f->m_density == 0.0f) + { + continue; + } + + b2MassData massData; + f->GetMassData(&massData); + m_mass += massData.mass; + localCenter += massData.mass * massData.center; + m_I += massData.I; + } + + // Compute center of mass. + if (m_mass > 0.0f) + { + m_invMass = 1.0f / m_mass; + localCenter *= m_invMass; + } + else + { + // Force all dynamic bodies to have a positive mass. + m_mass = 1.0f; + m_invMass = 1.0f; + } + + if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) + { + // Center the inertia about the center of mass. + m_I -= m_mass * b2Dot(localCenter, localCenter); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + + } + else + { + m_I = 0.0f; + m_invI = 0.0f; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = localCenter; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +void b2Body::SetMassData(const b2MassData* massData) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + if (m_type != b2_dynamicBody) + { + return; + } + + m_invMass = 0.0f; + m_I = 0.0f; + m_invI = 0.0f; + + m_mass = massData->mass; + if (m_mass <= 0.0f) + { + m_mass = 1.0f; + } + + m_invMass = 1.0f / m_mass; + + if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) + { + m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); + b2Assert(m_I > 0.0f); + m_invI = 1.0f / m_I; + } + + // Move center of mass. + b2Vec2 oldCenter = m_sweep.c; + m_sweep.localCenter = massData->center; + m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + + // Update center of mass velocity. + m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); +} + +bool b2Body::ShouldCollide(const b2Body* other) const +{ + // At least one body should be dynamic. + if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) + { + return false; + } + + // Does a joint prevent collision? + for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) + { + if (jn->other == other) + { + if (jn->joint->m_collideConnected == false) + { + return false; + } + } + } + + return true; +} + +void b2Body::SetTransform(const b2Vec2& position, float32 angle) +{ + b2Assert(m_world->IsLocked() == false); + if (m_world->IsLocked() == true) + { + return; + } + + m_xf.q.Set(angle); + m_xf.p = position; + + m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); + m_sweep.a = angle; + + m_sweep.c0 = m_sweep.c; + m_sweep.a0 = angle; + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, m_xf, m_xf); + } + + m_world->m_contactManager.FindNewContacts(); +} + +void b2Body::SynchronizeFixtures() +{ + b2Transform xf1; + xf1.q.Set(m_sweep.a0); + xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); + + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, xf1, m_xf); + } +} + +void b2Body::SetActive(bool flag) +{ + b2Assert(m_world->IsLocked() == false); + + if (flag == IsActive()) + { + return; + } + + if (flag) + { + m_flags |= e_activeFlag; + + // Create all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->CreateProxies(broadPhase, m_xf); + } + + // Contacts are created the next time step. + } + else + { + m_flags &= ~e_activeFlag; + + // Destroy all proxies. + b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->DestroyProxies(broadPhase); + } + + // Destroy the attached contacts. + b2ContactEdge* ce = m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_world->m_contactManager.Destroy(ce0->contact); + } + m_contactList = NULL; + } +} + +void b2Body::Dump() +{ + int32 bodyIndex = m_islandIndex; + + b2Log("{\n"); + b2Log(" b2BodyDef bd;\n"); + b2Log(" bd.type = b2BodyType(%d);\n", m_type); + b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); + b2Log(" bd.angle = %.15lef;\n", m_sweep.a); + b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); + b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); + b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); + b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); + b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); + b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); + b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); + b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); + b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); + b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); + b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); + b2Log("\n"); + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + b2Log(" {\n"); + f->Dump(bodyIndex); + b2Log(" }\n"); + } + b2Log("}\n"); +} \ No newline at end of file diff --git a/external/Box2D/Dynamics/b2Body.h b/external/Box2D/Dynamics/b2Body.h new file mode 100644 index 0000000000..e2d16bf630 --- /dev/null +++ b/external/Box2D/Dynamics/b2Body.h @@ -0,0 +1,846 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_BODY_H +#define B2_BODY_H + +#include +#include +#include + +class b2Fixture; +class b2Joint; +class b2Contact; +class b2Controller; +class b2World; +struct b2FixtureDef; +struct b2JointEdge; +struct b2ContactEdge; + +/// The body type. +/// static: zero mass, zero velocity, may be manually moved +/// kinematic: zero mass, non-zero velocity set by user, moved by solver +/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver +enum b2BodyType +{ + b2_staticBody = 0, + b2_kinematicBody, + b2_dynamicBody + + // TODO_ERIN + //b2_bulletBody, +}; + +/// A body definition holds all the data needed to construct a rigid body. +/// You can safely re-use body definitions. Shapes are added to a body after construction. +struct b2BodyDef +{ + /// This constructor sets the body definition default values. + b2BodyDef() + { + userData = NULL; + position.Set(0.0f, 0.0f); + angle = 0.0f; + linearVelocity.Set(0.0f, 0.0f); + angularVelocity = 0.0f; + linearDamping = 0.0f; + angularDamping = 0.0f; + allowSleep = true; + awake = true; + fixedRotation = false; + bullet = false; + type = b2_staticBody; + active = true; + gravityScale = 1.0f; + } + + /// The body type: static, kinematic, or dynamic. + /// Note: if a dynamic body would have zero mass, the mass is set to one. + b2BodyType type; + + /// The world position of the body. Avoid creating bodies at the origin + /// since this can lead to many overlapping shapes. + b2Vec2 position; + + /// The world angle of the body in radians. + float32 angle; + + /// The linear velocity of the body's origin in world co-ordinates. + b2Vec2 linearVelocity; + + /// The angular velocity of the body. + float32 angularVelocity; + + /// Linear damping is use to reduce the linear velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 linearDamping; + + /// Angular damping is use to reduce the angular velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 angularDamping; + + /// Set this flag to false if this body should never fall asleep. Note that + /// this increases CPU usage. + bool allowSleep; + + /// Is this body initially awake or sleeping? + bool awake; + + /// Should this body be prevented from rotating? Useful for characters. + bool fixedRotation; + + /// Is this a fast moving body that should be prevented from tunneling through + /// other moving bodies? Note that all bodies are prevented from tunneling through + /// kinematic and static bodies. This setting is only considered on dynamic bodies. + /// @warning You should use this flag sparingly since it increases processing time. + bool bullet; + + /// Does this body start out active? + bool active; + + /// Use this to store application specific body data. + void* userData; + + /// Scale the gravity applied to this body. + float32 gravityScale; +}; + +/// A rigid body. These are created via b2World::CreateBody. +class b2Body +{ +public: + /// Creates a fixture and attach it to this body. Use this function if you need + /// to set some fixture parameters, like friction. Otherwise you can create the + /// fixture directly from a shape. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// Contacts are not created until the next time step. + /// @param def the fixture definition. + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2FixtureDef* def); + + /// Creates a fixture from a shape and attach it to this body. + /// This is a convenience function. Use b2FixtureDef if you need to set parameters + /// like friction, restitution, user data, or filtering. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// @param shape the shape to be cloned. + /// @param density the shape density (set to zero for static bodies). + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2Shape* shape, float32 density); + + /// Destroy a fixture. This removes the fixture from the broad-phase and + /// destroys all contacts associated with this fixture. This will + /// automatically adjust the mass of the body if the body is dynamic and the + /// fixture has positive density. + /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. + /// @param fixture the fixture to be removed. + /// @warning This function is locked during callbacks. + void DestroyFixture(b2Fixture* fixture); + + /// Set the position of the body's origin and rotation. + /// This breaks any contacts and wakes the other bodies. + /// Manipulating a body's transform may cause non-physical behavior. + /// @param position the world position of the body's local origin. + /// @param angle the world rotation in radians. + void SetTransform(const b2Vec2& position, float32 angle); + + /// Get the body transform for the body's origin. + /// @return the world transform of the body's origin. + const b2Transform& GetTransform() const; + + /// Get the world body origin position. + /// @return the world position of the body's origin. + const b2Vec2& GetPosition() const; + + /// Get the angle in radians. + /// @return the current world rotation angle in radians. + float32 GetAngle() const; + + /// Get the world position of the center of mass. + const b2Vec2& GetWorldCenter() const; + + /// Get the local position of the center of mass. + const b2Vec2& GetLocalCenter() const; + + /// Set the linear velocity of the center of mass. + /// @param v the new linear velocity of the center of mass. + void SetLinearVelocity(const b2Vec2& v); + + /// Get the linear velocity of the center of mass. + /// @return the linear velocity of the center of mass. + b2Vec2 GetLinearVelocity() const; + + /// Set the angular velocity. + /// @param omega the new angular velocity in radians/second. + void SetAngularVelocity(float32 omega); + + /// Get the angular velocity. + /// @return the angular velocity in radians/second. + float32 GetAngularVelocity() const; + + /// Apply a force at a world point. If the force is not + /// applied at the center of mass, it will generate a torque and + /// affect the angular velocity. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + /// @param point the world position of the point of application. + void ApplyForce(const b2Vec2& force, const b2Vec2& point); + + /// Apply a force to the center of mass. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + void ApplyForceToCenter(const b2Vec2& force); + + /// Apply a torque. This affects the angular velocity + /// without affecting the linear velocity of the center of mass. + /// This wakes up the body. + /// @param torque about the z-axis (out of the screen), usually in N-m. + void ApplyTorque(float32 torque); + + /// Apply an impulse at a point. This immediately modifies the velocity. + /// It also modifies the angular velocity if the point of application + /// is not at the center of mass. This wakes up the body. + /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. + /// @param point the world position of the point of application. + void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point); + + /// Apply an angular impulse. + /// @param impulse the angular impulse in units of kg*m*m/s + void ApplyAngularImpulse(float32 impulse); + + /// Get the total mass of the body. + /// @return the mass, usually in kilograms (kg). + float32 GetMass() const; + + /// Get the rotational inertia of the body about the local origin. + /// @return the rotational inertia, usually in kg-m^2. + float32 GetInertia() const; + + /// Get the mass data of the body. + /// @return a struct containing the mass, inertia and center of the body. + void GetMassData(b2MassData* data) const; + + /// Set the mass properties to override the mass properties of the fixtures. + /// Note that this changes the center of mass position. + /// Note that creating or destroying fixtures can also alter the mass. + /// This function has no effect if the body isn't dynamic. + /// @param massData the mass properties. + void SetMassData(const b2MassData* data); + + /// This resets the mass properties to the sum of the mass properties of the fixtures. + /// This normally does not need to be called unless you called SetMassData to override + /// the mass and you later want to reset the mass. + void ResetMassData(); + + /// Get the world coordinates of a point given the local coordinates. + /// @param localPoint a point on the body measured relative the the body's origin. + /// @return the same point expressed in world coordinates. + b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; + + /// Get the world coordinates of a vector given the local coordinates. + /// @param localVector a vector fixed in the body. + /// @return the same vector expressed in world coordinates. + b2Vec2 GetWorldVector(const b2Vec2& localVector) const; + + /// Gets a local point relative to the body's origin given a world point. + /// @param a point in world coordinates. + /// @return the corresponding local point relative to the body's origin. + b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; + + /// Gets a local vector given a world vector. + /// @param a vector in world coordinates. + /// @return the corresponding local vector. + b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; + + /// Get the world linear velocity of a world point attached to this body. + /// @param a point in world coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; + + /// Get the world velocity of a local point. + /// @param a point in local coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; + + /// Get the linear damping of the body. + float32 GetLinearDamping() const; + + /// Set the linear damping of the body. + void SetLinearDamping(float32 linearDamping); + + /// Get the angular damping of the body. + float32 GetAngularDamping() const; + + /// Set the angular damping of the body. + void SetAngularDamping(float32 angularDamping); + + /// Get the gravity scale of the body. + float32 GetGravityScale() const; + + /// Set the gravity scale of the body. + void SetGravityScale(float32 scale); + + /// Set the type of this body. This may alter the mass and velocity. + void SetType(b2BodyType type); + + /// Get the type of this body. + b2BodyType GetType() const; + + /// Should this body be treated like a bullet for continuous collision detection? + void SetBullet(bool flag); + + /// Is this body treated like a bullet for continuous collision detection? + bool IsBullet() const; + + /// You can disable sleeping on this body. If you disable sleeping, the + /// body will be woken. + void SetSleepingAllowed(bool flag); + + /// Is this body allowed to sleep + bool IsSleepingAllowed() const; + + /// Set the sleep state of the body. A sleeping body has very + /// low CPU cost. + /// @param flag set to true to put body to sleep, false to wake it. + void SetAwake(bool flag); + + /// Get the sleeping state of this body. + /// @return true if the body is sleeping. + bool IsAwake() const; + + /// Set the active state of the body. An inactive body is not + /// simulated and cannot be collided with or woken up. + /// If you pass a flag of true, all fixtures will be added to the + /// broad-phase. + /// If you pass a flag of false, all fixtures will be removed from + /// the broad-phase and all contacts will be destroyed. + /// Fixtures and joints are otherwise unaffected. You may continue + /// to create/destroy fixtures and joints on inactive bodies. + /// Fixtures on an inactive body are implicitly inactive and will + /// not participate in collisions, ray-casts, or queries. + /// Joints connected to an inactive body are implicitly inactive. + /// An inactive body is still owned by a b2World object and remains + /// in the body list. + void SetActive(bool flag); + + /// Get the active state of the body. + bool IsActive() const; + + /// Set this body to have fixed rotation. This causes the mass + /// to be reset. + void SetFixedRotation(bool flag); + + /// Does this body have fixed rotation? + bool IsFixedRotation() const; + + /// Get the list of all fixtures attached to this body. + b2Fixture* GetFixtureList(); + const b2Fixture* GetFixtureList() const; + + /// Get the list of all joints attached to this body. + b2JointEdge* GetJointList(); + const b2JointEdge* GetJointList() const; + + /// Get the list of all contacts attached to this body. + /// @warning this list changes during the time step and you may + /// miss some collisions if you don't use b2ContactListener. + b2ContactEdge* GetContactList(); + const b2ContactEdge* GetContactList() const; + + /// Get the next body in the world's body list. + b2Body* GetNext(); + const b2Body* GetNext() const; + + /// Get the user data pointer that was provided in the body definition. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Get the parent world of this body. + b2World* GetWorld(); + const b2World* GetWorld() const; + + /// Dump this body to a log file + void Dump(); + +private: + + friend class b2World; + friend class b2Island; + friend class b2ContactManager; + friend class b2ContactSolver; + friend class b2Contact; + + friend class b2DistanceJoint; + friend class b2GearJoint; + friend class b2WheelJoint; + friend class b2MouseJoint; + friend class b2PrismaticJoint; + friend class b2PulleyJoint; + friend class b2RevoluteJoint; + friend class b2WeldJoint; + friend class b2FrictionJoint; + friend class b2RopeJoint; + + // m_flags + enum + { + e_islandFlag = 0x0001, + e_awakeFlag = 0x0002, + e_autoSleepFlag = 0x0004, + e_bulletFlag = 0x0008, + e_fixedRotationFlag = 0x0010, + e_activeFlag = 0x0020, + e_toiFlag = 0x0040 + }; + + b2Body(const b2BodyDef* bd, b2World* world); + ~b2Body(); + + void SynchronizeFixtures(); + void SynchronizeTransform(); + + // This is used to prevent connected bodies from colliding. + // It may lie, depending on the collideConnected flag. + bool ShouldCollide(const b2Body* other) const; + + void Advance(float32 t); + + b2BodyType m_type; + + uint16 m_flags; + + int32 m_islandIndex; + + b2Transform m_xf; // the body origin transform + b2Sweep m_sweep; // the swept motion for CCD + + b2Vec2 m_linearVelocity; + float32 m_angularVelocity; + + b2Vec2 m_force; + float32 m_torque; + + b2World* m_world; + b2Body* m_prev; + b2Body* m_next; + + b2Fixture* m_fixtureList; + int32 m_fixtureCount; + + b2JointEdge* m_jointList; + b2ContactEdge* m_contactList; + + float32 m_mass, m_invMass; + + // Rotational inertia about the center of mass. + float32 m_I, m_invI; + + float32 m_linearDamping; + float32 m_angularDamping; + float32 m_gravityScale; + + float32 m_sleepTime; + + void* m_userData; +}; + +inline b2BodyType b2Body::GetType() const +{ + return m_type; +} + +inline const b2Transform& b2Body::GetTransform() const +{ + return m_xf; +} + +inline const b2Vec2& b2Body::GetPosition() const +{ + return m_xf.p; +} + +inline float32 b2Body::GetAngle() const +{ + return m_sweep.a; +} + +inline const b2Vec2& b2Body::GetWorldCenter() const +{ + return m_sweep.c; +} + +inline const b2Vec2& b2Body::GetLocalCenter() const +{ + return m_sweep.localCenter; +} + +inline void b2Body::SetLinearVelocity(const b2Vec2& v) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (b2Dot(v,v) > 0.0f) + { + SetAwake(true); + } + + m_linearVelocity = v; +} + +inline b2Vec2 b2Body::GetLinearVelocity() const +{ + return m_linearVelocity; +} + +inline void b2Body::SetAngularVelocity(float32 w) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (w * w > 0.0f) + { + SetAwake(true); + } + + m_angularVelocity = w; +} + +inline float32 b2Body::GetAngularVelocity() const +{ + return m_angularVelocity; +} + +inline float32 b2Body::GetMass() const +{ + return m_mass; +} + +inline float32 b2Body::GetInertia() const +{ + return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); +} + +inline void b2Body::GetMassData(b2MassData* data) const +{ + data->mass = m_mass; + data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); + data->center = m_sweep.localCenter; +} + +inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const +{ + return b2Mul(m_xf, localPoint); +} + +inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const +{ + return b2Mul(m_xf.q, localVector); +} + +inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const +{ + return b2MulT(m_xf, worldPoint); +} + +inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const +{ + return b2MulT(m_xf.q, worldVector); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const +{ + return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const +{ + return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); +} + +inline float32 b2Body::GetLinearDamping() const +{ + return m_linearDamping; +} + +inline void b2Body::SetLinearDamping(float32 linearDamping) +{ + m_linearDamping = linearDamping; +} + +inline float32 b2Body::GetAngularDamping() const +{ + return m_angularDamping; +} + +inline void b2Body::SetAngularDamping(float32 angularDamping) +{ + m_angularDamping = angularDamping; +} + +inline float32 b2Body::GetGravityScale() const +{ + return m_gravityScale; +} + +inline void b2Body::SetGravityScale(float32 scale) +{ + m_gravityScale = scale; +} + +inline void b2Body::SetBullet(bool flag) +{ + if (flag) + { + m_flags |= e_bulletFlag; + } + else + { + m_flags &= ~e_bulletFlag; + } +} + +inline bool b2Body::IsBullet() const +{ + return (m_flags & e_bulletFlag) == e_bulletFlag; +} + +inline void b2Body::SetAwake(bool flag) +{ + if (flag) + { + if ((m_flags & e_awakeFlag) == 0) + { + m_flags |= e_awakeFlag; + m_sleepTime = 0.0f; + } + } + else + { + m_flags &= ~e_awakeFlag; + m_sleepTime = 0.0f; + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_force.SetZero(); + m_torque = 0.0f; + } +} + +inline bool b2Body::IsAwake() const +{ + return (m_flags & e_awakeFlag) == e_awakeFlag; +} + +inline bool b2Body::IsActive() const +{ + return (m_flags & e_activeFlag) == e_activeFlag; +} + +inline void b2Body::SetFixedRotation(bool flag) +{ + if (flag) + { + m_flags |= e_fixedRotationFlag; + } + else + { + m_flags &= ~e_fixedRotationFlag; + } + + ResetMassData(); +} + +inline bool b2Body::IsFixedRotation() const +{ + return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; +} + +inline void b2Body::SetSleepingAllowed(bool flag) +{ + if (flag) + { + m_flags |= e_autoSleepFlag; + } + else + { + m_flags &= ~e_autoSleepFlag; + SetAwake(true); + } +} + +inline bool b2Body::IsSleepingAllowed() const +{ + return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; +} + +inline b2Fixture* b2Body::GetFixtureList() +{ + return m_fixtureList; +} + +inline const b2Fixture* b2Body::GetFixtureList() const +{ + return m_fixtureList; +} + +inline b2JointEdge* b2Body::GetJointList() +{ + return m_jointList; +} + +inline const b2JointEdge* b2Body::GetJointList() const +{ + return m_jointList; +} + +inline b2ContactEdge* b2Body::GetContactList() +{ + return m_contactList; +} + +inline const b2ContactEdge* b2Body::GetContactList() const +{ + return m_contactList; +} + +inline b2Body* b2Body::GetNext() +{ + return m_next; +} + +inline const b2Body* b2Body::GetNext() const +{ + return m_next; +} + +inline void b2Body::SetUserData(void* data) +{ + m_userData = data; +} + +inline void* b2Body::GetUserData() const +{ + return m_userData; +} + +inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; + m_torque += b2Cross(point - m_sweep.c, force); +} + +inline void b2Body::ApplyForceToCenter(const b2Vec2& force) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_force += force; +} + +inline void b2Body::ApplyTorque(float32 torque) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + + m_torque += torque; +} + +inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_linearVelocity += m_invMass * impulse; + m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); +} + +inline void b2Body::ApplyAngularImpulse(float32 impulse) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (IsAwake() == false) + { + SetAwake(true); + } + m_angularVelocity += m_invI * impulse; +} + +inline void b2Body::SynchronizeTransform() +{ + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline void b2Body::Advance(float32 alpha) +{ + // Advance to the new safe time. This doesn't sync the broad-phase. + m_sweep.Advance(alpha); + m_sweep.c = m_sweep.c0; + m_sweep.a = m_sweep.a0; + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline b2World* b2Body::GetWorld() +{ + return m_world; +} + +inline const b2World* b2Body::GetWorld() const +{ + return m_world; +} + +#endif diff --git a/external/Box2D/Dynamics/b2ContactManager.cpp b/external/Box2D/Dynamics/b2ContactManager.cpp new file mode 100644 index 0000000000..c14cc4ce45 --- /dev/null +++ b/external/Box2D/Dynamics/b2ContactManager.cpp @@ -0,0 +1,293 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include + +b2ContactFilter b2_defaultFilter; +b2ContactListener b2_defaultListener; + +b2ContactManager::b2ContactManager() +{ + m_contactList = NULL; + m_contactCount = 0; + m_contactFilter = &b2_defaultFilter; + m_contactListener = &b2_defaultListener; + m_allocator = NULL; +} + +void b2ContactManager::Destroy(b2Contact* c) +{ + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + if (m_contactListener && c->IsTouching()) + { + m_contactListener->EndContact(c); + } + + // Remove from the world. + if (c->m_prev) + { + c->m_prev->m_next = c->m_next; + } + + if (c->m_next) + { + c->m_next->m_prev = c->m_prev; + } + + if (c == m_contactList) + { + m_contactList = c->m_next; + } + + // Remove from body 1 + if (c->m_nodeA.prev) + { + c->m_nodeA.prev->next = c->m_nodeA.next; + } + + if (c->m_nodeA.next) + { + c->m_nodeA.next->prev = c->m_nodeA.prev; + } + + if (&c->m_nodeA == bodyA->m_contactList) + { + bodyA->m_contactList = c->m_nodeA.next; + } + + // Remove from body 2 + if (c->m_nodeB.prev) + { + c->m_nodeB.prev->next = c->m_nodeB.next; + } + + if (c->m_nodeB.next) + { + c->m_nodeB.next->prev = c->m_nodeB.prev; + } + + if (&c->m_nodeB == bodyB->m_contactList) + { + bodyB->m_contactList = c->m_nodeB.next; + } + + // Call the factory. + b2Contact::Destroy(c, m_allocator); + --m_contactCount; +} + +// This is the top level collision call for the time step. Here +// all the narrow phase collision is processed for the world +// contact list. +void b2ContactManager::Collide() +{ + // Update awake contacts. + b2Contact* c = m_contactList; + while (c) + { + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Is this contact flagged for filtering? + if (c->m_flags & b2Contact::e_filterFlag) + { + // Should these bodies collide? + if (bodyB->ShouldCollide(bodyA) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // Clear the filtering flag. + c->m_flags &= ~b2Contact::e_filterFlag; + } + + bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; + bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; + + // At least one body must be awake and it must be dynamic or kinematic. + if (activeA == false && activeB == false) + { + c = c->GetNext(); + continue; + } + + int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; + int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; + bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); + + // Here we destroy contacts that cease to overlap in the broad-phase. + if (overlap == false) + { + b2Contact* cNuke = c; + c = cNuke->GetNext(); + Destroy(cNuke); + continue; + } + + // The contact persists. + c->Update(m_contactListener); + c = c->GetNext(); + } +} + +void b2ContactManager::FindNewContacts() +{ + m_broadPhase.UpdatePairs(this); +} + +void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) +{ + b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; + b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; + + b2Fixture* fixtureA = proxyA->fixture; + b2Fixture* fixtureB = proxyB->fixture; + + int32 indexA = proxyA->childIndex; + int32 indexB = proxyB->childIndex; + + b2Body* bodyA = fixtureA->GetBody(); + b2Body* bodyB = fixtureB->GetBody(); + + // Are the fixtures on the same body? + if (bodyA == bodyB) + { + return; + } + + // TODO_ERIN use a hash table to remove a potential bottleneck when both + // bodies have a lot of contacts. + // Does a contact already exist? + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + b2Fixture* fA = edge->contact->GetFixtureA(); + b2Fixture* fB = edge->contact->GetFixtureB(); + int32 iA = edge->contact->GetChildIndexA(); + int32 iB = edge->contact->GetChildIndexB(); + + if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) + { + // A contact already exists. + return; + } + + if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) + { + // A contact already exists. + return; + } + } + + edge = edge->next; + } + + // Does a joint override collision? Is at least one body dynamic? + if (bodyB->ShouldCollide(bodyA) == false) + { + return; + } + + // Check user filtering. + if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) + { + return; + } + + // Call the factory. + b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); + if (c == NULL) + { + return; + } + + // Contact creation may swap fixtures. + fixtureA = c->GetFixtureA(); + fixtureB = c->GetFixtureB(); + indexA = c->GetChildIndexA(); + indexB = c->GetChildIndexB(); + bodyA = fixtureA->GetBody(); + bodyB = fixtureB->GetBody(); + + // Insert into the world. + c->m_prev = NULL; + c->m_next = m_contactList; + if (m_contactList != NULL) + { + m_contactList->m_prev = c; + } + m_contactList = c; + + // Connect to island graph. + + // Connect to body A + c->m_nodeA.contact = c; + c->m_nodeA.other = bodyB; + + c->m_nodeA.prev = NULL; + c->m_nodeA.next = bodyA->m_contactList; + if (bodyA->m_contactList != NULL) + { + bodyA->m_contactList->prev = &c->m_nodeA; + } + bodyA->m_contactList = &c->m_nodeA; + + // Connect to body B + c->m_nodeB.contact = c; + c->m_nodeB.other = bodyA; + + c->m_nodeB.prev = NULL; + c->m_nodeB.next = bodyB->m_contactList; + if (bodyB->m_contactList != NULL) + { + bodyB->m_contactList->prev = &c->m_nodeB; + } + bodyB->m_contactList = &c->m_nodeB; + + // Wake up the bodies + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + ++m_contactCount; +} diff --git a/external/Box2D/Dynamics/b2ContactManager.h b/external/Box2D/Dynamics/b2ContactManager.h new file mode 100644 index 0000000000..9cb5718145 --- /dev/null +++ b/external/Box2D/Dynamics/b2ContactManager.h @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_CONTACT_MANAGER_H +#define B2_CONTACT_MANAGER_H + +#include + +class b2Contact; +class b2ContactFilter; +class b2ContactListener; +class b2BlockAllocator; + +// Delegate of b2World. +class b2ContactManager +{ +public: + b2ContactManager(); + + // Broad-phase callback. + void AddPair(void* proxyUserDataA, void* proxyUserDataB); + + void FindNewContacts(); + + void Destroy(b2Contact* c); + + void Collide(); + + b2BroadPhase m_broadPhase; + b2Contact* m_contactList; + int32 m_contactCount; + b2ContactFilter* m_contactFilter; + b2ContactListener* m_contactListener; + b2BlockAllocator* m_allocator; +}; + +#endif diff --git a/external/Box2D/Dynamics/b2Fixture.cpp b/external/Box2D/Dynamics/b2Fixture.cpp new file mode 100644 index 0000000000..774a78e5bb --- /dev/null +++ b/external/Box2D/Dynamics/b2Fixture.cpp @@ -0,0 +1,303 @@ +/* +* Copyright (c) 2006-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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2Fixture::b2Fixture() +{ + m_userData = NULL; + m_body = NULL; + m_next = NULL; + m_proxies = NULL; + m_proxyCount = 0; + m_shape = NULL; + m_density = 0.0f; +} + +void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) +{ + m_userData = def->userData; + m_friction = def->friction; + m_restitution = def->restitution; + + m_body = body; + m_next = NULL; + + m_filter = def->filter; + + m_isSensor = def->isSensor; + + m_shape = def->shape->Clone(allocator); + + // Reserve proxy space + int32 childCount = m_shape->GetChildCount(); + m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); + for (int32 i = 0; i < childCount; ++i) + { + m_proxies[i].fixture = NULL; + m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; + } + m_proxyCount = 0; + + m_density = def->density; +} + +void b2Fixture::Destroy(b2BlockAllocator* allocator) +{ + // The proxies must be destroyed before calling this. + b2Assert(m_proxyCount == 0); + + // Free the proxy array. + int32 childCount = m_shape->GetChildCount(); + allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); + m_proxies = NULL; + + // Free the child shape. + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + } + break; + + default: + b2Assert(false); + break; + } + + m_shape = NULL; +} + +void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) +{ + b2Assert(m_proxyCount == 0); + + // Create proxies in the broad-phase. + m_proxyCount = m_shape->GetChildCount(); + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + m_shape->ComputeAABB(&proxy->aabb, xf, i); + proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); + proxy->fixture = this; + proxy->childIndex = i; + } +} + +void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) +{ + // Destroy proxies in the broad-phase. + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + broadPhase->DestroyProxy(proxy->proxyId); + proxy->proxyId = b2BroadPhase::e_nullProxy; + } + + m_proxyCount = 0; +} + +void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) +{ + if (m_proxyCount == 0) + { + return; + } + + for (int32 i = 0; i < m_proxyCount; ++i) + { + b2FixtureProxy* proxy = m_proxies + i; + + // Compute an AABB that covers the swept shape (may miss some rotation effect). + b2AABB aabb1, aabb2; + m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); + m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); + + proxy->aabb.Combine(aabb1, aabb2); + + b2Vec2 displacement = transform2.p - transform1.p; + + broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); + } +} + +void b2Fixture::SetFilterData(const b2Filter& filter) +{ + m_filter = filter; + + Refilter(); +} + +void b2Fixture::Refilter() +{ + if (m_body == NULL) + { + return; + } + + // Flag associated contacts for filtering. + b2ContactEdge* edge = m_body->GetContactList(); + while (edge) + { + b2Contact* contact = edge->contact; + b2Fixture* fixtureA = contact->GetFixtureA(); + b2Fixture* fixtureB = contact->GetFixtureB(); + if (fixtureA == this || fixtureB == this) + { + contact->FlagForFiltering(); + } + + edge = edge->next; + } + + b2World* world = m_body->GetWorld(); + + if (world == NULL) + { + return; + } + + // Touch each proxy so that new pairs may be created + b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; + for (int32 i = 0; i < m_proxyCount; ++i) + { + broadPhase->TouchProxy(m_proxies[i].proxyId); + } +} + +void b2Fixture::SetSensor(bool sensor) +{ + if (sensor != m_isSensor) + { + m_body->SetAwake(true); + m_isSensor = sensor; + } +} + +void b2Fixture::Dump(int32 bodyIndex) +{ + b2Log(" b2FixtureDef fd;\n"); + b2Log(" fd.friction = %.15lef;\n", m_friction); + b2Log(" fd.restitution = %.15lef;\n", m_restitution); + b2Log(" fd.density = %.15lef;\n", m_density); + b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); + b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); + b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); + b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); + + switch (m_shape->m_type) + { + case b2Shape::e_circle: + { + b2CircleShape* s = (b2CircleShape*)m_shape; + b2Log(" b2CircleShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* s = (b2EdgeShape*)m_shape; + b2Log(" b2EdgeShape shape;\n"); + b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); + b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); + b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); + b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); + b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); + b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); + b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* s = (b2PolygonShape*)m_shape; + b2Log(" b2PolygonShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); + for (int32 i = 0; i < s->m_vertexCount; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* s = (b2ChainShape*)m_shape; + b2Log(" b2ChainShape shape;\n"); + b2Log(" b2Vec2 vs[%d];\n", s->m_count); + for (int32 i = 0; i < s->m_count; ++i) + { + b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); + } + b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); + b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); + b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); + b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); + b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); + } + break; + + default: + return; + } + + b2Log("\n"); + b2Log(" fd.shape = &shape;\n"); + b2Log("\n"); + b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); +} diff --git a/external/Box2D/Dynamics/b2Fixture.h b/external/Box2D/Dynamics/b2Fixture.h new file mode 100644 index 0000000000..d390410b93 --- /dev/null +++ b/external/Box2D/Dynamics/b2Fixture.h @@ -0,0 +1,345 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_FIXTURE_H +#define B2_FIXTURE_H + +#include +#include +#include + +class b2BlockAllocator; +class b2Body; +class b2BroadPhase; +class b2Fixture; + +/// This holds contact filtering data. +struct b2Filter +{ + b2Filter() + { + categoryBits = 0x0001; + maskBits = 0xFFFF; + groupIndex = 0; + } + + /// The collision category bits. Normally you would just set one bit. + uint16 categoryBits; + + /// The collision mask bits. This states the categories that this + /// shape would accept for collision. + uint16 maskBits; + + /// Collision groups allow a certain group of objects to never collide (negative) + /// or always collide (positive). Zero means no collision group. Non-zero group + /// filtering always wins against the mask bits. + int16 groupIndex; +}; + +/// A fixture definition is used to create a fixture. This class defines an +/// abstract fixture definition. You can reuse fixture definitions safely. +struct b2FixtureDef +{ + /// The constructor sets the default fixture definition values. + b2FixtureDef() + { + shape = NULL; + userData = NULL; + friction = 0.2f; + restitution = 0.0f; + density = 0.0f; + isSensor = false; + } + + /// The shape, this must be set. The shape will be cloned, so you + /// can create the shape on the stack. + const b2Shape* shape; + + /// Use this to store application specific fixture data. + void* userData; + + /// The friction coefficient, usually in the range [0,1]. + float32 friction; + + /// The restitution (elasticity) usually in the range [0,1]. + float32 restitution; + + /// The density, usually in kg/m^2. + float32 density; + + /// A sensor shape collects contact information but never generates a collision + /// response. + bool isSensor; + + /// Contact filtering data. + b2Filter filter; +}; + +/// This proxy is used internally to connect fixtures to the broad-phase. +struct b2FixtureProxy +{ + b2AABB aabb; + b2Fixture* fixture; + int32 childIndex; + int32 proxyId; +}; + +/// A fixture is used to attach a shape to a body for collision detection. A fixture +/// inherits its transform from its parent. Fixtures hold additional non-geometric data +/// such as friction, collision filters, etc. +/// Fixtures are created via b2Body::CreateFixture. +/// @warning you cannot reuse fixtures. +class b2Fixture +{ +public: + /// Get the type of the child shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + b2Shape::Type GetType() const; + + /// Get the child shape. You can modify the child shape, however you should not change the + /// number of vertices because this will crash some collision caching mechanisms. + /// Manipulating the shape may lead to non-physical behavior. + b2Shape* GetShape(); + const b2Shape* GetShape() const; + + /// Set if this fixture is a sensor. + void SetSensor(bool sensor); + + /// Is this fixture a sensor (non-solid)? + /// @return the true if the shape is a sensor. + bool IsSensor() const; + + /// Set the contact filtering data. This will not update contacts until the next time + /// step when either parent body is active and awake. + /// This automatically calls Refilter. + void SetFilterData(const b2Filter& filter); + + /// Get the contact filtering data. + const b2Filter& GetFilterData() const; + + /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. + void Refilter(); + + /// Get the parent body of this fixture. This is NULL if the fixture is not attached. + /// @return the parent body. + b2Body* GetBody(); + const b2Body* GetBody() const; + + /// Get the next fixture in the parent body's fixture list. + /// @return the next shape. + b2Fixture* GetNext(); + const b2Fixture* GetNext() const; + + /// Get the user data that was assigned in the fixture definition. Use this to + /// store your application specific data. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Test a point for containment in this fixture. + /// @param p a point in world coordinates. + bool TestPoint(const b2Vec2& p) const; + + /// Cast a ray against this shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; + + /// Get the mass data for this fixture. The mass data is based on the density and + /// the shape. The rotational inertia is about the shape's origin. This operation + /// may be expensive. + void GetMassData(b2MassData* massData) const; + + /// Set the density of this fixture. This will _not_ automatically adjust the mass + /// of the body. You must call b2Body::ResetMassData to update the body's mass. + void SetDensity(float32 density); + + /// Get the density of this fixture. + float32 GetDensity() const; + + /// Get the coefficient of friction. + float32 GetFriction() const; + + /// Set the coefficient of friction. This will _not_ change the friction of + /// existing contacts. + void SetFriction(float32 friction); + + /// Get the coefficient of restitution. + float32 GetRestitution() const; + + /// Set the coefficient of restitution. This will _not_ change the restitution of + /// existing contacts. + void SetRestitution(float32 restitution); + + /// Get the fixture's AABB. This AABB may be enlarge and/or stale. + /// If you need a more accurate AABB, compute it using the shape and + /// the body transform. + const b2AABB& GetAABB(int32 childIndex) const; + + /// Dump this fixture to the log file. + void Dump(int32 bodyIndex); + +protected: + + friend class b2Body; + friend class b2World; + friend class b2Contact; + friend class b2ContactManager; + + b2Fixture(); + + // We need separation create/destroy functions from the constructor/destructor because + // the destructor cannot access the allocator (no destructor arguments allowed by C++). + void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); + void Destroy(b2BlockAllocator* allocator); + + // These support body activation/deactivation. + void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); + void DestroyProxies(b2BroadPhase* broadPhase); + + void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); + + float32 m_density; + + b2Fixture* m_next; + b2Body* m_body; + + b2Shape* m_shape; + + float32 m_friction; + float32 m_restitution; + + b2FixtureProxy* m_proxies; + int32 m_proxyCount; + + b2Filter m_filter; + + bool m_isSensor; + + void* m_userData; +}; + +inline b2Shape::Type b2Fixture::GetType() const +{ + return m_shape->GetType(); +} + +inline b2Shape* b2Fixture::GetShape() +{ + return m_shape; +} + +inline const b2Shape* b2Fixture::GetShape() const +{ + return m_shape; +} + +inline bool b2Fixture::IsSensor() const +{ + return m_isSensor; +} + +inline const b2Filter& b2Fixture::GetFilterData() const +{ + return m_filter; +} + +inline void* b2Fixture::GetUserData() const +{ + return m_userData; +} + +inline void b2Fixture::SetUserData(void* data) +{ + m_userData = data; +} + +inline b2Body* b2Fixture::GetBody() +{ + return m_body; +} + +inline const b2Body* b2Fixture::GetBody() const +{ + return m_body; +} + +inline b2Fixture* b2Fixture::GetNext() +{ + return m_next; +} + +inline const b2Fixture* b2Fixture::GetNext() const +{ + return m_next; +} + +inline void b2Fixture::SetDensity(float32 density) +{ + b2Assert(b2IsValid(density) && density >= 0.0f); + m_density = density; +} + +inline float32 b2Fixture::GetDensity() const +{ + return m_density; +} + +inline float32 b2Fixture::GetFriction() const +{ + return m_friction; +} + +inline void b2Fixture::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Fixture::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Fixture::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline bool b2Fixture::TestPoint(const b2Vec2& p) const +{ + return m_shape->TestPoint(m_body->GetTransform(), p); +} + +inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const +{ + return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); +} + +inline void b2Fixture::GetMassData(b2MassData* massData) const +{ + m_shape->ComputeMass(massData, m_density); +} + +inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const +{ + b2Assert(0 <= childIndex && childIndex < m_proxyCount); + return m_proxies[childIndex].aabb; +} + +#endif diff --git a/external/Box2D/Dynamics/b2Island.cpp b/external/Box2D/Dynamics/b2Island.cpp new file mode 100644 index 0000000000..e767d383d5 --- /dev/null +++ b/external/Box2D/Dynamics/b2Island.cpp @@ -0,0 +1,539 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +Position Correction Notes +========================= +I tried the several algorithms for position correction of the 2D revolute joint. +I looked at these systems: +- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. +- suspension bridge with 30 1m long planks of length 1m. +- multi-link chain with 30 1m long links. + +Here are the algorithms: + +Baumgarte - A fraction of the position error is added to the velocity error. There is no +separate position solver. + +Pseudo Velocities - After the velocity solver and position integration, +the position error, Jacobian, and effective mass are recomputed. Then +the velocity constraints are solved with pseudo velocities and a fraction +of the position error is added to the pseudo velocity error. The pseudo +velocities are initialized to zero and there is no warm-starting. After +the position solver, the pseudo velocities are added to the positions. +This is also called the First Order World method or the Position LCP method. + +Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the +position error is re-computed for each constraint and the positions are updated +after the constraint is solved. The radius vectors (aka Jacobians) are +re-computed too (otherwise the algorithm has horrible instability). The pseudo +velocity states are not needed because they are effectively zero at the beginning +of each iteration. Since we have the current position error, we allow the +iterations to terminate early if the error becomes smaller than b2_linearSlop. + +Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed +each time a constraint is solved. + +Here are the results: +Baumgarte - this is the cheapest algorithm but it has some stability problems, +especially with the bridge. The chain links separate easily close to the root +and they jitter as they struggle to pull together. This is one of the most common +methods in the field. The big drawback is that the position correction artificially +affects the momentum, thus leading to instabilities and false bounce. I used a +bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller +factor makes joints and contacts more spongy. + +Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is +stable. However, joints still separate with large angular velocities. Drag the +simple pendulum in a circle quickly and the joint will separate. The chain separates +easily and does not recover. I used a bias factor of 0.2. A larger value lead to +the bridge collapsing when a heavy cube drops on it. + +Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo +Velocities, but in other ways it is worse. The bridge and chain are much more +stable, but the simple pendulum goes unstable at high angular velocities. + +Full NGS - stable in all tests. The joints display good stiffness. The bridge +still sags, but this is better than infinite forces. + +Recommendations +Pseudo Velocities are not really worthwhile because the bridge and chain cannot +recover from joint separation. In other cases the benefit over Baumgarte is small. + +Modified NGS is not a robust method for the revolute joint due to the violent +instability seen in the simple pendulum. Perhaps it is viable with other constraint +types, especially scalar constraints where the effective mass is a scalar. + +This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities +and is very fast. I don't think we can escape Baumgarte, especially in highly +demanding cases where high constraint fidelity is not needed. + +Full NGS is robust and easy on the eyes. I recommend this as an option for +higher fidelity simulation and certainly for suspension bridges and long chains. +Full NGS might be a good choice for ragdolls, especially motorized ragdolls where +joint separation can be problematic. The number of NGS iterations can be reduced +for better performance without harming robustness much. + +Each joint in a can be handled differently in the position solver. So I recommend +a system where the user can select the algorithm on a per joint basis. I would +probably default to the slower Full NGS and let the user select the faster +Baumgarte method in performance critical scenarios. +*/ + +/* +Cache Performance + +The Box2D solvers are dominated by cache misses. Data structures are designed +to increase the number of cache hits. Much of misses are due to random access +to body data. The constraint structures are iterated over linearly, which leads +to few cache misses. + +The bodies are not accessed during iteration. Instead read only data, such as +the mass values are stored with the constraints. The mutable data are the constraint +impulses and the bodies velocities/positions. The impulses are held inside the +constraint structures. The body velocities/positions are held in compact, temporary +arrays to increase the number of cache hits. Linear and angular velocity are +stored in a single array since multiple arrays lead to multiple misses. +*/ + +/* +2D Rotation + +R = [cos(theta) -sin(theta)] + [sin(theta) cos(theta) ] + +thetaDot = omega + +Let q1 = cos(theta), q2 = sin(theta). +R = [q1 -q2] + [q2 q1] + +q1Dot = -thetaDot * q2 +q2Dot = thetaDot * q1 + +q1_new = q1_old - dt * w * q2 +q2_new = q2_old + dt * w * q1 +then normalize. + +This might be faster than computing sin+cos. +However, we can compute sin+cos of the same angle fast. +*/ + +b2Island::b2Island( + int32 bodyCapacity, + int32 contactCapacity, + int32 jointCapacity, + b2StackAllocator* allocator, + b2ContactListener* listener) +{ + m_bodyCapacity = bodyCapacity; + m_contactCapacity = contactCapacity; + m_jointCapacity = jointCapacity; + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + + m_allocator = allocator; + m_listener = listener; + + m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); + m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); + m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); + + m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); + m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); +} + +b2Island::~b2Island() +{ + // Warning: the order should reverse the constructor order. + m_allocator->Free(m_positions); + m_allocator->Free(m_velocities); + m_allocator->Free(m_joints); + m_allocator->Free(m_contacts); + m_allocator->Free(m_bodies); +} + +void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) +{ + b2Timer timer; + + float32 h = step.dt; + + // Integrate velocities and apply damping. Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + + b2Vec2 c = b->m_sweep.c; + float32 a = b->m_sweep.a; + b2Vec2 v = b->m_linearVelocity; + float32 w = b->m_angularVelocity; + + // Store positions for continuous collision. + b->m_sweep.c0 = b->m_sweep.c; + b->m_sweep.a0 = b->m_sweep.a; + + if (b->m_type == b2_dynamicBody) + { + // Integrate velocities. + v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); + w += h * b->m_invI * b->m_torque; + + // Apply damping. + // ODE: dv/dt + c * v = 0 + // Solution: v(t) = v0 * exp(-c * t) + // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) + // v2 = exp(-c * dt) * v1 + // Taylor expansion: + // v2 = (1.0f - c * dt) * v1 + v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); + w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); + } + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + timer.Reset(); + + // Solver data + b2SolverData solverData; + solverData.step = step; + solverData.positions = m_positions; + solverData.velocities = m_velocities; + + // Initialize velocity constraints. + b2ContactSolverDef contactSolverDef; + contactSolverDef.step = step; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + contactSolverDef.allocator = m_allocator; + + b2ContactSolver contactSolver(&contactSolverDef); + contactSolver.InitializeVelocityConstraints(); + + if (step.warmStarting) + { + contactSolver.WarmStart(); + } + + for (int32 i = 0; i < m_jointCount; ++i) + { + m_joints[i]->InitVelocityConstraints(solverData); + } + + profile->solveInit = timer.GetMilliseconds(); + + // Solve velocity constraints + timer.Reset(); + for (int32 i = 0; i < step.velocityIterations; ++i) + { + for (int32 j = 0; j < m_jointCount; ++j) + { + m_joints[j]->SolveVelocityConstraints(solverData); + } + + contactSolver.SolveVelocityConstraints(); + } + + // Store impulses for warm starting + contactSolver.StoreImpulses(); + profile->solveVelocity = timer.GetMilliseconds(); + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + } + + // Solve position constraints + timer.Reset(); + bool positionSolved = false; + for (int32 i = 0; i < step.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolvePositionConstraints(); + + bool jointsOkay = true; + for (int32 i = 0; i < m_jointCount; ++i) + { + bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); + jointsOkay = jointsOkay && jointOkay; + } + + if (contactsOkay && jointsOkay) + { + // Exit early if the position errors are small. + positionSolved = true; + break; + } + } + + // Copy state buffers back to the bodies + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* body = m_bodies[i]; + body->m_sweep.c = m_positions[i].c; + body->m_sweep.a = m_positions[i].a; + body->m_linearVelocity = m_velocities[i].v; + body->m_angularVelocity = m_velocities[i].w; + body->SynchronizeTransform(); + } + + profile->solvePosition = timer.GetMilliseconds(); + + Report(contactSolver.m_velocityConstraints); + + if (allowSleep) + { + float32 minSleepTime = b2_maxFloat; + + const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; + const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; + + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + continue; + } + + if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || + b->m_angularVelocity * b->m_angularVelocity > angTolSqr || + b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) + { + b->m_sleepTime = 0.0f; + minSleepTime = 0.0f; + } + else + { + b->m_sleepTime += h; + minSleepTime = b2Min(minSleepTime, b->m_sleepTime); + } + } + + if (minSleepTime >= b2_timeToSleep && positionSolved) + { + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + b->SetAwake(false); + } + } + } +} + +void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) +{ + b2Assert(toiIndexA < m_bodyCount); + b2Assert(toiIndexB < m_bodyCount); + + // Initialize the body state. + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Body* b = m_bodies[i]; + m_positions[i].c = b->m_sweep.c; + m_positions[i].a = b->m_sweep.a; + m_velocities[i].v = b->m_linearVelocity; + m_velocities[i].w = b->m_angularVelocity; + } + + b2ContactSolverDef contactSolverDef; + contactSolverDef.contacts = m_contacts; + contactSolverDef.count = m_contactCount; + contactSolverDef.allocator = m_allocator; + contactSolverDef.step = subStep; + contactSolverDef.positions = m_positions; + contactSolverDef.velocities = m_velocities; + b2ContactSolver contactSolver(&contactSolverDef); + + // Solve position constraints. + for (int32 i = 0; i < subStep.positionIterations; ++i) + { + bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); + if (contactsOkay) + { + break; + } + } + +#if 0 + // Is the new position really safe? + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + b2DistanceInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.transformA = bA->GetTransform(); + input.transformB = bB->GetTransform(); + input.useRadii = false; + + b2DistanceOutput output; + b2SimplexCache cache; + cache.count = 0; + b2Distance(&output, &cache, &input); + + if (output.distance == 0 || cache.count == 3) + { + cache.count += 0; + } + } +#endif + + // Leap of faith to new safe state. + m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; + m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; + m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; + m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; + + // No warm starting is needed for TOI events because warm + // starting impulses were applied in the discrete solver. + contactSolver.InitializeVelocityConstraints(); + + // Solve velocity constraints. + for (int32 i = 0; i < subStep.velocityIterations; ++i) + { + contactSolver.SolveVelocityConstraints(); + } + + // Don't store the TOI contact forces for warm starting + // because they can be quite large. + + float32 h = subStep.dt; + + // Integrate positions + for (int32 i = 0; i < m_bodyCount; ++i) + { + b2Vec2 c = m_positions[i].c; + float32 a = m_positions[i].a; + b2Vec2 v = m_velocities[i].v; + float32 w = m_velocities[i].w; + + // Check for large velocities + b2Vec2 translation = h * v; + if (b2Dot(translation, translation) > b2_maxTranslationSquared) + { + float32 ratio = b2_maxTranslation / translation.Length(); + v *= ratio; + } + + float32 rotation = h * w; + if (rotation * rotation > b2_maxRotationSquared) + { + float32 ratio = b2_maxRotation / b2Abs(rotation); + w *= ratio; + } + + // Integrate + c += h * v; + a += h * w; + + m_positions[i].c = c; + m_positions[i].a = a; + m_velocities[i].v = v; + m_velocities[i].w = w; + + // Sync bodies + b2Body* body = m_bodies[i]; + body->m_sweep.c = c; + body->m_sweep.a = a; + body->m_linearVelocity = v; + body->m_angularVelocity = w; + body->SynchronizeTransform(); + } + + Report(contactSolver.m_velocityConstraints); +} + +void b2Island::Report(const b2ContactVelocityConstraint* constraints) +{ + if (m_listener == NULL) + { + return; + } + + for (int32 i = 0; i < m_contactCount; ++i) + { + b2Contact* c = m_contacts[i]; + + const b2ContactVelocityConstraint* vc = constraints + i; + + b2ContactImpulse impulse; + impulse.count = vc->pointCount; + for (int32 j = 0; j < vc->pointCount; ++j) + { + impulse.normalImpulses[j] = vc->points[j].normalImpulse; + impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; + } + + m_listener->PostSolve(c, &impulse); + } +} diff --git a/external/Box2D/Dynamics/b2Island.h b/external/Box2D/Dynamics/b2Island.h new file mode 100644 index 0000000000..e0a6e41fc3 --- /dev/null +++ b/external/Box2D/Dynamics/b2Island.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_ISLAND_H +#define B2_ISLAND_H + +#include +#include +#include + +class b2Contact; +class b2Joint; +class b2StackAllocator; +class b2ContactListener; +struct b2ContactVelocityConstraint; +struct b2Profile; + +/// This is an internal class. +class b2Island +{ +public: + b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, + b2StackAllocator* allocator, b2ContactListener* listener); + ~b2Island(); + + void Clear() + { + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + } + + void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); + + void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); + + void Add(b2Body* body) + { + b2Assert(m_bodyCount < m_bodyCapacity); + body->m_islandIndex = m_bodyCount; + m_bodies[m_bodyCount] = body; + ++m_bodyCount; + } + + void Add(b2Contact* contact) + { + b2Assert(m_contactCount < m_contactCapacity); + m_contacts[m_contactCount++] = contact; + } + + void Add(b2Joint* joint) + { + b2Assert(m_jointCount < m_jointCapacity); + m_joints[m_jointCount++] = joint; + } + + void Report(const b2ContactVelocityConstraint* constraints); + + b2StackAllocator* m_allocator; + b2ContactListener* m_listener; + + b2Body** m_bodies; + b2Contact** m_contacts; + b2Joint** m_joints; + + b2Position* m_positions; + b2Velocity* m_velocities; + + int32 m_bodyCount; + int32 m_jointCount; + int32 m_contactCount; + + int32 m_bodyCapacity; + int32 m_contactCapacity; + int32 m_jointCapacity; +}; + +#endif diff --git a/external/Box2D/Dynamics/b2TimeStep.h b/external/Box2D/Dynamics/b2TimeStep.h new file mode 100644 index 0000000000..30d723fcc3 --- /dev/null +++ b/external/Box2D/Dynamics/b2TimeStep.h @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_TIME_STEP_H +#define B2_TIME_STEP_H + +#include + +/// Profiling data. Times are in milliseconds. +struct b2Profile +{ + float32 step; + float32 collide; + float32 solve; + float32 solveInit; + float32 solveVelocity; + float32 solvePosition; + float32 broadphase; + float32 solveTOI; +}; + +/// This is an internal structure. +struct b2TimeStep +{ + float32 dt; // time step + float32 inv_dt; // inverse time step (0 if dt == 0). + float32 dtRatio; // dt * inv_dt0 + int32 velocityIterations; + int32 positionIterations; + bool warmStarting; +}; + +/// This is an internal structure. +struct b2Position +{ + b2Vec2 c; + float32 a; +}; + +/// This is an internal structure. +struct b2Velocity +{ + b2Vec2 v; + float32 w; +}; + +/// Solver Data +struct b2SolverData +{ + b2TimeStep step; + b2Position* positions; + b2Velocity* velocities; +}; + +#endif diff --git a/external/Box2D/Dynamics/b2World.cpp b/external/Box2D/Dynamics/b2World.cpp new file mode 100644 index 0000000000..8a0aff5114 --- /dev/null +++ b/external/Box2D/Dynamics/b2World.cpp @@ -0,0 +1,1316 @@ +/* +* Copyright (c) 2006-2011 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +b2World::b2World(const b2Vec2& gravity) +{ + m_destructionListener = NULL; + m_debugDraw = NULL; + + m_bodyList = NULL; + m_jointList = NULL; + + m_bodyCount = 0; + m_jointCount = 0; + + m_warmStarting = true; + m_continuousPhysics = true; + m_subStepping = false; + + m_stepComplete = true; + + m_allowSleep = true; + m_gravity = gravity; + + m_flags = e_clearForces; + + m_inv_dt0 = 0.0f; + + m_contactManager.m_allocator = &m_blockAllocator; + + memset(&m_profile, 0, sizeof(b2Profile)); +} + +b2World::~b2World() +{ + // Some shapes allocate using b2Alloc. + b2Body* b = m_bodyList; + while (b) + { + b2Body* bNext = b->m_next; + + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* fNext = f->m_next; + f->m_proxyCount = 0; + f->Destroy(&m_blockAllocator); + f = fNext; + } + + b = bNext; + } +} + +void b2World::SetDestructionListener(b2DestructionListener* listener) +{ + m_destructionListener = listener; +} + +void b2World::SetContactFilter(b2ContactFilter* filter) +{ + m_contactManager.m_contactFilter = filter; +} + +void b2World::SetContactListener(b2ContactListener* listener) +{ + m_contactManager.m_contactListener = listener; +} + +void b2World::SetDebugDraw(b2Draw* debugDraw) +{ + m_debugDraw = debugDraw; +} + +b2Body* b2World::CreateBody(const b2BodyDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); + b2Body* b = new (mem) b2Body(def, this); + + // Add to world doubly linked list. + b->m_prev = NULL; + b->m_next = m_bodyList; + if (m_bodyList) + { + m_bodyList->m_prev = b; + } + m_bodyList = b; + ++m_bodyCount; + + return b; +} + +void b2World::DestroyBody(b2Body* b) +{ + b2Assert(m_bodyCount > 0); + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + // Delete the attached joints. + b2JointEdge* je = b->m_jointList; + while (je) + { + b2JointEdge* je0 = je; + je = je->next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(je0->joint); + } + + DestroyJoint(je0->joint); + + b->m_jointList = je; + } + b->m_jointList = NULL; + + // Delete the attached contacts. + b2ContactEdge* ce = b->m_contactList; + while (ce) + { + b2ContactEdge* ce0 = ce; + ce = ce->next; + m_contactManager.Destroy(ce0->contact); + } + b->m_contactList = NULL; + + // Delete the attached fixtures. This destroys broad-phase proxies. + b2Fixture* f = b->m_fixtureList; + while (f) + { + b2Fixture* f0 = f; + f = f->m_next; + + if (m_destructionListener) + { + m_destructionListener->SayGoodbye(f0); + } + + f0->DestroyProxies(&m_contactManager.m_broadPhase); + f0->Destroy(&m_blockAllocator); + f0->~b2Fixture(); + m_blockAllocator.Free(f0, sizeof(b2Fixture)); + + b->m_fixtureList = f; + b->m_fixtureCount -= 1; + } + b->m_fixtureList = NULL; + b->m_fixtureCount = 0; + + // Remove world body list. + if (b->m_prev) + { + b->m_prev->m_next = b->m_next; + } + + if (b->m_next) + { + b->m_next->m_prev = b->m_prev; + } + + if (b == m_bodyList) + { + m_bodyList = b->m_next; + } + + --m_bodyCount; + b->~b2Body(); + m_blockAllocator.Free(b, sizeof(b2Body)); +} + +b2Joint* b2World::CreateJoint(const b2JointDef* def) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return NULL; + } + + b2Joint* j = b2Joint::Create(def, &m_blockAllocator); + + // Connect to the world list. + j->m_prev = NULL; + j->m_next = m_jointList; + if (m_jointList) + { + m_jointList->m_prev = j; + } + m_jointList = j; + ++m_jointCount; + + // Connect to the bodies' doubly linked lists. + j->m_edgeA.joint = j; + j->m_edgeA.other = j->m_bodyB; + j->m_edgeA.prev = NULL; + j->m_edgeA.next = j->m_bodyA->m_jointList; + if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; + j->m_bodyA->m_jointList = &j->m_edgeA; + + j->m_edgeB.joint = j; + j->m_edgeB.other = j->m_bodyA; + j->m_edgeB.prev = NULL; + j->m_edgeB.next = j->m_bodyB->m_jointList; + if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; + j->m_bodyB->m_jointList = &j->m_edgeB; + + b2Body* bodyA = def->bodyA; + b2Body* bodyB = def->bodyB; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (def->collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } + + // Note: creating a joint doesn't wake the bodies. + + return j; +} + +void b2World::DestroyJoint(b2Joint* j) +{ + b2Assert(IsLocked() == false); + if (IsLocked()) + { + return; + } + + bool collideConnected = j->m_collideConnected; + + // Remove from the doubly linked list. + if (j->m_prev) + { + j->m_prev->m_next = j->m_next; + } + + if (j->m_next) + { + j->m_next->m_prev = j->m_prev; + } + + if (j == m_jointList) + { + m_jointList = j->m_next; + } + + // Disconnect from island graph. + b2Body* bodyA = j->m_bodyA; + b2Body* bodyB = j->m_bodyB; + + // Wake up connected bodies. + bodyA->SetAwake(true); + bodyB->SetAwake(true); + + // Remove from body 1. + if (j->m_edgeA.prev) + { + j->m_edgeA.prev->next = j->m_edgeA.next; + } + + if (j->m_edgeA.next) + { + j->m_edgeA.next->prev = j->m_edgeA.prev; + } + + if (&j->m_edgeA == bodyA->m_jointList) + { + bodyA->m_jointList = j->m_edgeA.next; + } + + j->m_edgeA.prev = NULL; + j->m_edgeA.next = NULL; + + // Remove from body 2 + if (j->m_edgeB.prev) + { + j->m_edgeB.prev->next = j->m_edgeB.next; + } + + if (j->m_edgeB.next) + { + j->m_edgeB.next->prev = j->m_edgeB.prev; + } + + if (&j->m_edgeB == bodyB->m_jointList) + { + bodyB->m_jointList = j->m_edgeB.next; + } + + j->m_edgeB.prev = NULL; + j->m_edgeB.next = NULL; + + b2Joint::Destroy(j, &m_blockAllocator); + + b2Assert(m_jointCount > 0); + --m_jointCount; + + // If the joint prevents collisions, then flag any contacts for filtering. + if (collideConnected == false) + { + b2ContactEdge* edge = bodyB->GetContactList(); + while (edge) + { + if (edge->other == bodyA) + { + // Flag the contact for filtering at the next time step (where either + // body is awake). + edge->contact->FlagForFiltering(); + } + + edge = edge->next; + } + } +} + +// +void b2World::SetAllowSleeping(bool flag) +{ + if (flag == m_allowSleep) + { + return; + } + + m_allowSleep = flag; + if (m_allowSleep == false) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->SetAwake(true); + } + } +} + +// Find islands, integrate and solve constraints, solve position constraints +void b2World::Solve(const b2TimeStep& step) +{ + m_profile.solveInit = 0.0f; + m_profile.solveVelocity = 0.0f; + m_profile.solvePosition = 0.0f; + + // Size the island for the worst case. + b2Island island(m_bodyCount, + m_contactManager.m_contactCount, + m_jointCount, + &m_stackAllocator, + m_contactManager.m_contactListener); + + // Clear all the island flags. + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + c->m_flags &= ~b2Contact::e_islandFlag; + } + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_islandFlag = false; + } + + // Build and simulate all awake islands. + int32 stackSize = m_bodyCount; + b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); + for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) + { + if (seed->m_flags & b2Body::e_islandFlag) + { + continue; + } + + if (seed->IsAwake() == false || seed->IsActive() == false) + { + continue; + } + + // The seed can be dynamic or kinematic. + if (seed->GetType() == b2_staticBody) + { + continue; + } + + // Reset island and stack. + island.Clear(); + int32 stackCount = 0; + stack[stackCount++] = seed; + seed->m_flags |= b2Body::e_islandFlag; + + // Perform a depth first search (DFS) on the constraint graph. + while (stackCount > 0) + { + // Grab the next body off the stack and add it to the island. + b2Body* b = stack[--stackCount]; + b2Assert(b->IsActive() == true); + island.Add(b); + + // Make sure the body is awake. + b->SetAwake(true); + + // To keep islands as small as possible, we don't + // propagate islands across static bodies. + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Search all contacts connected to this body. + for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) + { + b2Contact* contact = ce->contact; + + // Has this contact already been added to an island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Is this contact solid and touching? + if (contact->IsEnabled() == false || + contact->IsTouching() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + island.Add(contact); + contact->m_flags |= b2Contact::e_islandFlag; + + b2Body* other = ce->other; + + // Was the other body already added to this island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + + // Search all joints connect to this body. + for (b2JointEdge* je = b->m_jointList; je; je = je->next) + { + if (je->joint->m_islandFlag == true) + { + continue; + } + + b2Body* other = je->other; + + // Don't simulate joints connected to inactive bodies. + if (other->IsActive() == false) + { + continue; + } + + island.Add(je->joint); + je->joint->m_islandFlag = true; + + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + b2Assert(stackCount < stackSize); + stack[stackCount++] = other; + other->m_flags |= b2Body::e_islandFlag; + } + } + + b2Profile profile; + island.Solve(&profile, step, m_gravity, m_allowSleep); + m_profile.solveInit += profile.solveInit; + m_profile.solveVelocity += profile.solveVelocity; + m_profile.solvePosition += profile.solvePosition; + + // Post solve cleanup. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + // Allow static bodies to participate in other islands. + b2Body* b = island.m_bodies[i]; + if (b->GetType() == b2_staticBody) + { + b->m_flags &= ~b2Body::e_islandFlag; + } + } + } + + m_stackAllocator.Free(stack); + + { + b2Timer timer; + // Synchronize fixtures, check for out of range bodies. + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + // If a body was not in an island then it did not move. + if ((b->m_flags & b2Body::e_islandFlag) == 0) + { + continue; + } + + if (b->GetType() == b2_staticBody) + { + continue; + } + + // Update fixtures (for broad-phase). + b->SynchronizeFixtures(); + } + + // Look for new contacts. + m_contactManager.FindNewContacts(); + m_profile.broadphase = timer.GetMilliseconds(); + } +} + +// Find TOI contacts and solve them. +void b2World::SolveTOI(const b2TimeStep& step) +{ + b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); + + if (m_stepComplete) + { + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_flags &= ~b2Body::e_islandFlag; + b->m_sweep.alpha0 = 0.0f; + } + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Invalidate TOI + c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + c->m_toiCount = 0; + c->m_toi = 1.0f; + } + } + + // Find TOI events and solve them. + for (;;) + { + // Find the first TOI. + b2Contact* minContact = NULL; + float32 minAlpha = 1.0f; + + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) + { + // Is this contact disabled? + if (c->IsEnabled() == false) + { + continue; + } + + // Prevent excessive sub-stepping. + if (c->m_toiCount > b2_maxSubSteps) + { + continue; + } + + float32 alpha = 1.0f; + if (c->m_flags & b2Contact::e_toiFlag) + { + // This contact has a valid cached TOI. + alpha = c->m_toi; + } + else + { + b2Fixture* fA = c->GetFixtureA(); + b2Fixture* fB = c->GetFixtureB(); + + // Is there a sensor? + if (fA->IsSensor() || fB->IsSensor()) + { + continue; + } + + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2BodyType typeA = bA->m_type; + b2BodyType typeB = bB->m_type; + b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); + + bool activeA = bA->IsAwake() && typeA != b2_staticBody; + bool activeB = bB->IsAwake() && typeB != b2_staticBody; + + // Is at least one body active (awake and dynamic or kinematic)? + if (activeA == false && activeB == false) + { + continue; + } + + bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; + bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; + + // Are these two non-bullet dynamic bodies? + if (collideA == false && collideB == false) + { + continue; + } + + // Compute the TOI for this contact. + // Put the sweeps onto the same time interval. + float32 alpha0 = bA->m_sweep.alpha0; + + if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) + { + alpha0 = bB->m_sweep.alpha0; + bA->m_sweep.Advance(alpha0); + } + else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) + { + alpha0 = bA->m_sweep.alpha0; + bB->m_sweep.Advance(alpha0); + } + + b2Assert(alpha0 < 1.0f); + + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + + // Compute the time of impact in interval [0, minTOI] + b2TOIInput input; + input.proxyA.Set(fA->GetShape(), indexA); + input.proxyB.Set(fB->GetShape(), indexB); + input.sweepA = bA->m_sweep; + input.sweepB = bB->m_sweep; + input.tMax = 1.0f; + + b2TOIOutput output; + b2TimeOfImpact(&output, &input); + + // Beta is the fraction of the remaining portion of the . + float32 beta = output.t; + if (output.state == b2TOIOutput::e_touching) + { + alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); + } + else + { + alpha = 1.0f; + } + + c->m_toi = alpha; + c->m_flags |= b2Contact::e_toiFlag; + } + + if (alpha < minAlpha) + { + // This is the minimum TOI found so far. + minContact = c; + minAlpha = alpha; + } + } + + if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) + { + // No more TOI events. Done! + m_stepComplete = true; + break; + } + + // Advance the bodies to the TOI. + b2Fixture* fA = minContact->GetFixtureA(); + b2Fixture* fB = minContact->GetFixtureB(); + b2Body* bA = fA->GetBody(); + b2Body* bB = fB->GetBody(); + + b2Sweep backup1 = bA->m_sweep; + b2Sweep backup2 = bB->m_sweep; + + bA->Advance(minAlpha); + bB->Advance(minAlpha); + + // The TOI contact likely has some new contact points. + minContact->Update(m_contactManager.m_contactListener); + minContact->m_flags &= ~b2Contact::e_toiFlag; + ++minContact->m_toiCount; + + // Is the contact solid? + if (minContact->IsEnabled() == false || minContact->IsTouching() == false) + { + // Restore the sweeps. + minContact->SetEnabled(false); + bA->m_sweep = backup1; + bB->m_sweep = backup2; + bA->SynchronizeTransform(); + bB->SynchronizeTransform(); + continue; + } + + bA->SetAwake(true); + bB->SetAwake(true); + + // Build the island + island.Clear(); + island.Add(bA); + island.Add(bB); + island.Add(minContact); + + bA->m_flags |= b2Body::e_islandFlag; + bB->m_flags |= b2Body::e_islandFlag; + minContact->m_flags |= b2Contact::e_islandFlag; + + // Get contacts on bodyA and bodyB. + b2Body* bodies[2] = {bA, bB}; + for (int32 i = 0; i < 2; ++i) + { + b2Body* body = bodies[i]; + if (body->m_type == b2_dynamicBody) + { + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + if (island.m_bodyCount == island.m_bodyCapacity) + { + break; + } + + if (island.m_contactCount == island.m_contactCapacity) + { + break; + } + + b2Contact* contact = ce->contact; + + // Has this contact already been added to the island? + if (contact->m_flags & b2Contact::e_islandFlag) + { + continue; + } + + // Only add static, kinematic, or bullet bodies. + b2Body* other = ce->other; + if (other->m_type == b2_dynamicBody && + body->IsBullet() == false && other->IsBullet() == false) + { + continue; + } + + // Skip sensors. + bool sensorA = contact->m_fixtureA->m_isSensor; + bool sensorB = contact->m_fixtureB->m_isSensor; + if (sensorA || sensorB) + { + continue; + } + + // Tentatively advance the body to the TOI. + b2Sweep backup = other->m_sweep; + if ((other->m_flags & b2Body::e_islandFlag) == 0) + { + other->Advance(minAlpha); + } + + // Update the contact points + contact->Update(m_contactManager.m_contactListener); + + // Was the contact disabled by the user? + if (contact->IsEnabled() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Are there contact points? + if (contact->IsTouching() == false) + { + other->m_sweep = backup; + other->SynchronizeTransform(); + continue; + } + + // Add the contact to the island + contact->m_flags |= b2Contact::e_islandFlag; + island.Add(contact); + + // Has the other body already been added to the island? + if (other->m_flags & b2Body::e_islandFlag) + { + continue; + } + + // Add the other body to the island. + other->m_flags |= b2Body::e_islandFlag; + + if (other->m_type != b2_staticBody) + { + other->SetAwake(true); + } + + island.Add(other); + } + } + } + + b2TimeStep subStep; + subStep.dt = (1.0f - minAlpha) * step.dt; + subStep.inv_dt = 1.0f / subStep.dt; + subStep.dtRatio = 1.0f; + subStep.positionIterations = 20; + subStep.velocityIterations = step.velocityIterations; + subStep.warmStarting = false; + island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); + + // Reset island flags and synchronize broad-phase proxies. + for (int32 i = 0; i < island.m_bodyCount; ++i) + { + b2Body* body = island.m_bodies[i]; + body->m_flags &= ~b2Body::e_islandFlag; + + if (body->m_type != b2_dynamicBody) + { + continue; + } + + body->SynchronizeFixtures(); + + // Invalidate all contact TOIs on this displaced body. + for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) + { + ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); + } + } + + // Commit fixture proxy movements to the broad-phase so that new contacts are created. + // Also, some contacts can be destroyed. + m_contactManager.FindNewContacts(); + + if (m_subStepping) + { + m_stepComplete = false; + break; + } + } +} + +void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) +{ + b2Timer stepTimer; + + // If new fixtures were added, we need to find the new contacts. + if (m_flags & e_newFixture) + { + m_contactManager.FindNewContacts(); + m_flags &= ~e_newFixture; + } + + m_flags |= e_locked; + + b2TimeStep step; + step.dt = dt; + step.velocityIterations = velocityIterations; + step.positionIterations = positionIterations; + if (dt > 0.0f) + { + step.inv_dt = 1.0f / dt; + } + else + { + step.inv_dt = 0.0f; + } + + step.dtRatio = m_inv_dt0 * dt; + + step.warmStarting = m_warmStarting; + + // Update contacts. This is where some contacts are destroyed. + { + b2Timer timer; + m_contactManager.Collide(); + m_profile.collide = timer.GetMilliseconds(); + } + + // Integrate velocities, solve velocity constraints, and integrate positions. + if (m_stepComplete && step.dt > 0.0f) + { + b2Timer timer; + Solve(step); + m_profile.solve = timer.GetMilliseconds(); + } + + // Handle TOI events. + if (m_continuousPhysics && step.dt > 0.0f) + { + b2Timer timer; + SolveTOI(step); + m_profile.solveTOI = timer.GetMilliseconds(); + } + + if (step.dt > 0.0f) + { + m_inv_dt0 = step.inv_dt; + } + + if (m_flags & e_clearForces) + { + ClearForces(); + } + + m_flags &= ~e_locked; + + m_profile.step = stepTimer.GetMilliseconds(); +} + +void b2World::ClearForces() +{ + for (b2Body* body = m_bodyList; body; body = body->GetNext()) + { + body->m_force.SetZero(); + body->m_torque = 0.0f; + } +} + +struct b2WorldQueryWrapper +{ + bool QueryCallback(int32 proxyId) + { + b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); + return callback->ReportFixture(proxy->fixture); + } + + const b2BroadPhase* broadPhase; + b2QueryCallback* callback; +}; + +void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const +{ + b2WorldQueryWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + m_contactManager.m_broadPhase.Query(&wrapper, aabb); +} + +struct b2WorldRayCastWrapper +{ + float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) + { + void* userData = broadPhase->GetUserData(proxyId); + b2FixtureProxy* proxy = (b2FixtureProxy*)userData; + b2Fixture* fixture = proxy->fixture; + int32 index = proxy->childIndex; + b2RayCastOutput output; + bool hit = fixture->RayCast(&output, input, index); + + if (hit) + { + float32 fraction = output.fraction; + b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; + return callback->ReportFixture(fixture, point, output.normal, fraction); + } + + return input.maxFraction; + } + + const b2BroadPhase* broadPhase; + b2RayCastCallback* callback; +}; + +void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const +{ + b2WorldRayCastWrapper wrapper; + wrapper.broadPhase = &m_contactManager.m_broadPhase; + wrapper.callback = callback; + b2RayCastInput input; + input.maxFraction = 1.0f; + input.p1 = point1; + input.p2 = point2; + m_contactManager.m_broadPhase.RayCast(&wrapper, input); +} + +void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) +{ + switch (fixture->GetType()) + { + case b2Shape::e_circle: + { + b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); + + b2Vec2 center = b2Mul(xf, circle->m_p); + float32 radius = circle->m_radius; + b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); + + m_debugDraw->DrawSolidCircle(center, radius, axis, color); + } + break; + + case b2Shape::e_edge: + { + b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); + b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); + b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); + m_debugDraw->DrawSegment(v1, v2, color); + } + break; + + case b2Shape::e_chain: + { + b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); + int32 count = chain->m_count; + const b2Vec2* vertices = chain->m_vertices; + + b2Vec2 v1 = b2Mul(xf, vertices[0]); + for (int32 i = 1; i < count; ++i) + { + b2Vec2 v2 = b2Mul(xf, vertices[i]); + m_debugDraw->DrawSegment(v1, v2, color); + m_debugDraw->DrawCircle(v1, 0.05f, color); + v1 = v2; + } + } + break; + + case b2Shape::e_polygon: + { + b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); + int32 vertexCount = poly->m_vertexCount; + b2Assert(vertexCount <= b2_maxPolygonVertices); + b2Vec2 vertices[b2_maxPolygonVertices]; + + for (int32 i = 0; i < vertexCount; ++i) + { + vertices[i] = b2Mul(xf, poly->m_vertices[i]); + } + + m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); + } + break; + + default: + break; + } +} + +void b2World::DrawJoint(b2Joint* joint) +{ + b2Body* bodyA = joint->GetBodyA(); + b2Body* bodyB = joint->GetBodyB(); + const b2Transform& xf1 = bodyA->GetTransform(); + const b2Transform& xf2 = bodyB->GetTransform(); + b2Vec2 x1 = xf1.p; + b2Vec2 x2 = xf2.p; + b2Vec2 p1 = joint->GetAnchorA(); + b2Vec2 p2 = joint->GetAnchorB(); + + b2Color color(0.5f, 0.8f, 0.8f); + + switch (joint->GetType()) + { + case e_distanceJoint: + m_debugDraw->DrawSegment(p1, p2, color); + break; + + case e_pulleyJoint: + { + b2PulleyJoint* pulley = (b2PulleyJoint*)joint; + b2Vec2 s1 = pulley->GetGroundAnchorA(); + b2Vec2 s2 = pulley->GetGroundAnchorB(); + m_debugDraw->DrawSegment(s1, p1, color); + m_debugDraw->DrawSegment(s2, p2, color); + m_debugDraw->DrawSegment(s1, s2, color); + } + break; + + case e_mouseJoint: + // don't draw this + break; + + default: + m_debugDraw->DrawSegment(x1, p1, color); + m_debugDraw->DrawSegment(p1, p2, color); + m_debugDraw->DrawSegment(x2, p2, color); + } +} + +void b2World::DrawDebugData() +{ + if (m_debugDraw == NULL) + { + return; + } + + uint32 flags = m_debugDraw->GetFlags(); + + if (flags & b2Draw::e_shapeBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + const b2Transform& xf = b->GetTransform(); + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + if (b->IsActive() == false) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); + } + else if (b->GetType() == b2_staticBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); + } + else if (b->GetType() == b2_kinematicBody) + { + DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); + } + else if (b->IsAwake() == false) + { + DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); + } + else + { + DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); + } + } + } + } + + if (flags & b2Draw::e_jointBit) + { + for (b2Joint* j = m_jointList; j; j = j->GetNext()) + { + DrawJoint(j); + } + } + + if (flags & b2Draw::e_pairBit) + { + b2Color color(0.3f, 0.9f, 0.9f); + for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) + { + //b2Fixture* fixtureA = c->GetFixtureA(); + //b2Fixture* fixtureB = c->GetFixtureB(); + + //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); + //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); + + //m_debugDraw->DrawSegment(cA, cB, color); + } + } + + if (flags & b2Draw::e_aabbBit) + { + b2Color color(0.9f, 0.3f, 0.9f); + b2BroadPhase* bp = &m_contactManager.m_broadPhase; + + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + if (b->IsActive() == false) + { + continue; + } + + for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) + { + for (int32 i = 0; i < f->m_proxyCount; ++i) + { + b2FixtureProxy* proxy = f->m_proxies + i; + b2AABB aabb = bp->GetFatAABB(proxy->proxyId); + b2Vec2 vs[4]; + vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); + vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); + vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); + vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); + + m_debugDraw->DrawPolygon(vs, 4, color); + } + } + } + } + + if (flags & b2Draw::e_centerOfMassBit) + { + for (b2Body* b = m_bodyList; b; b = b->GetNext()) + { + b2Transform xf = b->GetTransform(); + xf.p = b->GetWorldCenter(); + m_debugDraw->DrawTransform(xf); + } + } +} + +int32 b2World::GetProxyCount() const +{ + return m_contactManager.m_broadPhase.GetProxyCount(); +} + +int32 b2World::GetTreeHeight() const +{ + return m_contactManager.m_broadPhase.GetTreeHeight(); +} + +int32 b2World::GetTreeBalance() const +{ + return m_contactManager.m_broadPhase.GetTreeBalance(); +} + +float32 b2World::GetTreeQuality() const +{ + return m_contactManager.m_broadPhase.GetTreeQuality(); +} + +void b2World::Dump() +{ + if ((m_flags & e_locked) == e_locked) + { + return; + } + + b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); + b2Log("m_world->SetGravity(g);\n"); + + b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); + b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); + int32 i = 0; + for (b2Body* b = m_bodyList; b; b = b->m_next) + { + b->m_islandIndex = i; + b->Dump(); + ++i; + } + + i = 0; + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + j->m_index = i; + ++i; + } + + // First pass on joints, skip gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type == e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + // Second pass on joints, only gear joints. + for (b2Joint* j = m_jointList; j; j = j->m_next) + { + if (j->m_type != e_gearJoint) + { + continue; + } + + b2Log("{\n"); + j->Dump(); + b2Log("}\n"); + } + + b2Log("b2Free(joints);\n"); + b2Log("b2Free(bodies);\n"); + b2Log("joints = NULL;\n"); + b2Log("bodies = NULL;\n"); +} diff --git a/external/Box2D/Dynamics/b2World.h b/external/Box2D/Dynamics/b2World.h new file mode 100644 index 0000000000..f207930511 --- /dev/null +++ b/external/Box2D/Dynamics/b2World.h @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2006-2011 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. +*/ + +#ifndef B2_WORLD_H +#define B2_WORLD_H + +#include +#include +#include +#include +#include +#include + +struct b2AABB; +struct b2BodyDef; +struct b2Color; +struct b2JointDef; +class b2Body; +class b2Draw; +class b2Fixture; +class b2Joint; + +/// The world class manages all physics entities, dynamic simulation, +/// and asynchronous queries. The world also contains efficient memory +/// management facilities. +class b2World +{ +public: + /// Construct a world object. + /// @param gravity the world gravity vector. + b2World(const b2Vec2& gravity); + + /// Destruct the world. All physics entities are destroyed and all heap memory is released. + ~b2World(); + + /// Register a destruction listener. The listener is owned by you and must + /// remain in scope. + void SetDestructionListener(b2DestructionListener* listener); + + /// Register a contact filter to provide specific control over collision. + /// Otherwise the default filter is used (b2_defaultFilter). The listener is + /// owned by you and must remain in scope. + void SetContactFilter(b2ContactFilter* filter); + + /// Register a contact event listener. The listener is owned by you and must + /// remain in scope. + void SetContactListener(b2ContactListener* listener); + + /// Register a routine for debug drawing. The debug draw functions are called + /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// by you and must remain in scope. + void SetDebugDraw(b2Draw* debugDraw); + + /// Create a rigid body given a definition. No reference to the definition + /// is retained. + /// @warning This function is locked during callbacks. + b2Body* CreateBody(const b2BodyDef* def); + + /// Destroy a rigid body given a definition. No reference to the definition + /// is retained. This function is locked during callbacks. + /// @warning This automatically deletes all associated shapes and joints. + /// @warning This function is locked during callbacks. + void DestroyBody(b2Body* body); + + /// Create a joint to constrain bodies together. No reference to the definition + /// is retained. This may cause the connected bodies to cease colliding. + /// @warning This function is locked during callbacks. + b2Joint* CreateJoint(const b2JointDef* def); + + /// Destroy a joint. This may cause the connected bodies to begin colliding. + /// @warning This function is locked during callbacks. + void DestroyJoint(b2Joint* joint); + + /// Take a time step. This performs collision detection, integration, + /// and constraint solution. + /// @param timeStep the amount of time to simulate, this should not vary. + /// @param velocityIterations for the velocity constraint solver. + /// @param positionIterations for the position constraint solver. + void Step( float32 timeStep, + int32 velocityIterations, + int32 positionIterations); + + /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically + /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. + /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain + /// a fixed sized time step under a variable frame-rate. + /// When you perform sub-stepping you will disable auto clearing of forces and instead call + /// ClearForces after all sub-steps are complete in one pass of your game loop. + /// @see SetAutoClearForces + void ClearForces(); + + /// Call this to draw shapes and other debug draw data. + void DrawDebugData(); + + /// Query the world for all fixtures that potentially overlap the + /// provided AABB. + /// @param callback a user implemented callback class. + /// @param aabb the query box. + void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; + + /// Ray-cast the world for all fixtures in the path of the ray. Your callback + /// controls whether you get the closest point, any point, or n-points. + /// The ray-cast ignores shapes that contain the starting point. + /// @param callback a user implemented callback class. + /// @param point1 the ray starting point + /// @param point2 the ray ending point + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + + /// Get the world body list. With the returned body, use b2Body::GetNext to get + /// the next body in the world list. A NULL body indicates the end of the list. + /// @return the head of the world body list. + b2Body* GetBodyList(); + const b2Body* GetBodyList() const; + + /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get + /// the next joint in the world list. A NULL joint indicates the end of the list. + /// @return the head of the world joint list. + b2Joint* GetJointList(); + const b2Joint* GetJointList() const; + + /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get + /// the next contact in the world list. A NULL contact indicates the end of the list. + /// @return the head of the world contact list. + /// @warning contacts are created and destroyed in the middle of a time step. + /// Use b2ContactListener to avoid missing contacts. + b2Contact* GetContactList(); + const b2Contact* GetContactList() const; + + /// Enable/disable sleep. + void SetAllowSleeping(bool flag); + bool GetAllowSleeping() const { return m_allowSleep; } + + /// Enable/disable warm starting. For testing. + void SetWarmStarting(bool flag) { m_warmStarting = flag; } + bool GetWarmStarting() const { return m_warmStarting; } + + /// Enable/disable continuous physics. For testing. + void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } + bool GetContinuousPhysics() const { return m_continuousPhysics; } + + /// Enable/disable single stepped continuous physics. For testing. + void SetSubStepping(bool flag) { m_subStepping = flag; } + bool GetSubStepping() const { return m_subStepping; } + + /// Get the number of broad-phase proxies. + int32 GetProxyCount() const; + + /// Get the number of bodies. + int32 GetBodyCount() const; + + /// Get the number of joints. + int32 GetJointCount() const; + + /// Get the number of contacts (each may have 0 or more contact points). + int32 GetContactCount() const; + + /// Get the height of the dynamic tree. + int32 GetTreeHeight() const; + + /// Get the balance of the dynamic tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the dynamic tree. The smaller the better. + /// The minimum is 1. + float32 GetTreeQuality() const; + + /// Change the global gravity vector. + void SetGravity(const b2Vec2& gravity); + + /// Get the global gravity vector. + b2Vec2 GetGravity() const; + + /// Is the world locked (in the middle of a time step). + bool IsLocked() const; + + /// Set flag to control automatic clearing of forces after each time step. + void SetAutoClearForces(bool flag); + + /// Get the flag that controls automatic clearing of forces after each time step. + bool GetAutoClearForces() const; + + /// Get the contact manager for testing. + const b2ContactManager& GetContactManager() const; + + /// Get the current profile. + const b2Profile& GetProfile() const; + + /// Dump the world into the log file. + /// @warning this should be called outside of a time step. + void Dump(); + +private: + + // m_flags + enum + { + e_newFixture = 0x0001, + e_locked = 0x0002, + e_clearForces = 0x0004 + }; + + friend class b2Body; + friend class b2Fixture; + friend class b2ContactManager; + friend class b2Controller; + + void Solve(const b2TimeStep& step); + void SolveTOI(const b2TimeStep& step); + + void DrawJoint(b2Joint* joint); + void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); + + b2BlockAllocator m_blockAllocator; + b2StackAllocator m_stackAllocator; + + int32 m_flags; + + b2ContactManager m_contactManager; + + b2Body* m_bodyList; + b2Joint* m_jointList; + + int32 m_bodyCount; + int32 m_jointCount; + + b2Vec2 m_gravity; + bool m_allowSleep; + + b2DestructionListener* m_destructionListener; + b2Draw* m_debugDraw; + + // This is used to compute the time step ratio to + // support a variable time step. + float32 m_inv_dt0; + + // These are for debugging the solver. + bool m_warmStarting; + bool m_continuousPhysics; + bool m_subStepping; + + bool m_stepComplete; + + b2Profile m_profile; +}; + +inline b2Body* b2World::GetBodyList() +{ + return m_bodyList; +} + +inline const b2Body* b2World::GetBodyList() const +{ + return m_bodyList; +} + +inline b2Joint* b2World::GetJointList() +{ + return m_jointList; +} + +inline const b2Joint* b2World::GetJointList() const +{ + return m_jointList; +} + +inline b2Contact* b2World::GetContactList() +{ + return m_contactManager.m_contactList; +} + +inline const b2Contact* b2World::GetContactList() const +{ + return m_contactManager.m_contactList; +} + +inline int32 b2World::GetBodyCount() const +{ + return m_bodyCount; +} + +inline int32 b2World::GetJointCount() const +{ + return m_jointCount; +} + +inline int32 b2World::GetContactCount() const +{ + return m_contactManager.m_contactCount; +} + +inline void b2World::SetGravity(const b2Vec2& gravity) +{ + m_gravity = gravity; +} + +inline b2Vec2 b2World::GetGravity() const +{ + return m_gravity; +} + +inline bool b2World::IsLocked() const +{ + return (m_flags & e_locked) == e_locked; +} + +inline void b2World::SetAutoClearForces(bool flag) +{ + if (flag) + { + m_flags |= e_clearForces; + } + else + { + m_flags &= ~e_clearForces; + } +} + +/// Get the flag that controls automatic clearing of forces after each time step. +inline bool b2World::GetAutoClearForces() const +{ + return (m_flags & e_clearForces) == e_clearForces; +} + +inline const b2ContactManager& b2World::GetContactManager() const +{ + return m_contactManager; +} + +inline const b2Profile& b2World::GetProfile() const +{ + return m_profile; +} + +#endif diff --git a/external/Box2D/Dynamics/b2WorldCallbacks.cpp b/external/Box2D/Dynamics/b2WorldCallbacks.cpp new file mode 100644 index 0000000000..48ad0cc46a --- /dev/null +++ b/external/Box2D/Dynamics/b2WorldCallbacks.cpp @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2006-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 +#include + +// Return true if contact calculations should be performed between these two shapes. +// If you implement your own collision filter you may want to build from this implementation. +bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) +{ + const b2Filter& filterA = fixtureA->GetFilterData(); + const b2Filter& filterB = fixtureB->GetFilterData(); + + if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) + { + return filterA.groupIndex > 0; + } + + bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; + return collide; +} diff --git a/external/Box2D/Dynamics/b2WorldCallbacks.h b/external/Box2D/Dynamics/b2WorldCallbacks.h new file mode 100644 index 0000000000..86c04e3e32 --- /dev/null +++ b/external/Box2D/Dynamics/b2WorldCallbacks.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2006-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. +*/ + +#ifndef B2_WORLD_CALLBACKS_H +#define B2_WORLD_CALLBACKS_H + +#include + +struct b2Vec2; +struct b2Transform; +class b2Fixture; +class b2Body; +class b2Joint; +class b2Contact; +struct b2ContactResult; +struct b2Manifold; + +/// Joints and fixtures are destroyed when their associated +/// body is destroyed. Implement this listener so that you +/// may nullify references to these joints and shapes. +class b2DestructionListener +{ +public: + virtual ~b2DestructionListener() {} + + /// Called when any joint is about to be destroyed due + /// to the destruction of one of its attached bodies. + virtual void SayGoodbye(b2Joint* joint) = 0; + + /// Called when any fixture is about to be destroyed due + /// to the destruction of its parent body. + virtual void SayGoodbye(b2Fixture* fixture) = 0; +}; + +/// Implement this class to provide collision filtering. In other words, you can implement +/// this class if you want finer control over contact creation. +class b2ContactFilter +{ +public: + virtual ~b2ContactFilter() {} + + /// Return true if contact calculations should be performed between these two shapes. + /// @warning for performance reasons this is only called when the AABBs begin to overlap. + virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); +}; + +/// Contact impulses for reporting. Impulses are used instead of forces because +/// sub-step forces may approach infinity for rigid body collisions. These +/// match up one-to-one with the contact points in b2Manifold. +struct b2ContactImpulse +{ + float32 normalImpulses[b2_maxManifoldPoints]; + float32 tangentImpulses[b2_maxManifoldPoints]; + int32 count; +}; + +/// Implement this class to get contact information. You can use these results for +/// things like sounds and game logic. You can also get contact results by +/// traversing the contact lists after the time step. However, you might miss +/// some contacts because continuous physics leads to sub-stepping. +/// Additionally you may receive multiple callbacks for the same contact in a +/// single time step. +/// You should strive to make your callbacks efficient because there may be +/// many callbacks per time step. +/// @warning You cannot create/destroy Box2D entities inside these callbacks. +class b2ContactListener +{ +public: + virtual ~b2ContactListener() {} + + /// Called when two fixtures begin to touch. + virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// Called when two fixtures cease to touch. + virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// This is called after a contact is updated. This allows you to inspect a + /// contact before it goes to the solver. If you are careful, you can modify the + /// contact manifold (e.g. disable contact). + /// A copy of the old manifold is provided so that you can detect changes. + /// Note: this is called only for awake bodies. + /// Note: this is called even when the number of contact points is zero. + /// Note: this is not called for sensors. + /// Note: if you set the number of contact points to zero, you will not + /// get an EndContact callback. However, you may get a BeginContact callback + /// the next step. + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + B2_NOT_USED(contact); + B2_NOT_USED(oldManifold); + } + + /// This lets you inspect a contact after the solver is finished. This is useful + /// for inspecting impulses. + /// Note: the contact manifold does not include time of impact impulses, which can be + /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly + /// in a separate data structure. + /// Note: this is only called for contacts that are touching, solid, and awake. + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + B2_NOT_USED(contact); + B2_NOT_USED(impulse); + } +}; + +/// Callback class for AABB queries. +/// See b2World::Query +class b2QueryCallback +{ +public: + virtual ~b2QueryCallback() {} + + /// Called for each fixture found in the query AABB. + /// @return false to terminate the query. + virtual bool ReportFixture(b2Fixture* fixture) = 0; +}; + +/// Callback class for ray casts. +/// See b2World::RayCast +class b2RayCastCallback +{ +public: + virtual ~b2RayCastCallback() {} + + /// Called for each fixture found in the query. You control how the ray cast + /// proceeds by returning a float: + /// return -1: ignore this fixture and continue + /// return 0: terminate the ray cast + /// return fraction: clip the ray to this point + /// return 1: don't clip the ray and continue + /// @param fixture the fixture hit by the ray + /// @param point the point of initial intersection + /// @param normal the normal vector at the point of intersection + /// @return -1 to filter, 0 to terminate, fraction to clip the ray for + /// closest hit, 1 to continue + virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) = 0; +}; + +#endif diff --git a/external/Box2D/Rope/b2Rope.cpp b/external/Box2D/Rope/b2Rope.cpp new file mode 100644 index 0000000000..9bf671aec9 --- /dev/null +++ b/external/Box2D/Rope/b2Rope.cpp @@ -0,0 +1,259 @@ +/* +* Copyright (c) 2011 Erin Catto http://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 +#include + +b2Rope::b2Rope() +{ + m_count = 0; + m_ps = NULL; + m_p0s = NULL; + m_vs = NULL; + m_ims = NULL; + m_Ls = NULL; + m_as = NULL; + m_gravity.SetZero(); + m_k2 = 1.0f; + m_k3 = 0.1f; +} + +b2Rope::~b2Rope() +{ + b2Free(m_ps); + b2Free(m_p0s); + b2Free(m_vs); + b2Free(m_ims); + b2Free(m_Ls); + b2Free(m_as); +} + +void b2Rope::Initialize(const b2RopeDef* def) +{ + b2Assert(def->count >= 3); + m_count = def->count; + m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); + m_ims = (float32*)b2Alloc(m_count * sizeof(float32)); + + for (int32 i = 0; i < m_count; ++i) + { + m_ps[i] = def->vertices[i]; + m_p0s[i] = def->vertices[i]; + m_vs[i].SetZero(); + + float32 m = def->masses[i]; + if (m > 0.0f) + { + m_ims[i] = 1.0f / m; + } + else + { + m_ims[i] = 0.0f; + } + } + + int32 count2 = m_count - 1; + int32 count3 = m_count - 2; + m_Ls = (float32*)b2Alloc(count2 * sizeof(float32)); + m_as = (float32*)b2Alloc(count3 * sizeof(float32)); + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i+1]; + m_Ls[i] = b2Distance(p1, p2); + } + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + m_as[i] = b2Atan2(a, b); + } + + m_gravity = def->gravity; + m_damping = def->damping; + m_k2 = def->k2; + m_k3 = def->k3; +} + +void b2Rope::Step(float32 h, int32 iterations) +{ + if (h == 0.0) + { + return; + } + + float32 d = expf(- h * m_damping); + + for (int32 i = 0; i < m_count; ++i) + { + m_p0s[i] = m_ps[i]; + if (m_ims[i] > 0.0f) + { + m_vs[i] += h * m_gravity; + } + m_vs[i] *= d; + m_ps[i] += h * m_vs[i]; + + } + + for (int32 i = 0; i < iterations; ++i) + { + SolveC2(); + SolveC3(); + SolveC2(); + } + + float32 inv_h = 1.0f / h; + for (int32 i = 0; i < m_count; ++i) + { + m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]); + } +} + +void b2Rope::SolveC2() +{ + int32 count2 = m_count - 1; + + for (int32 i = 0; i < count2; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + + b2Vec2 d = p2 - p1; + float32 L = d.Normalize(); + + float32 im1 = m_ims[i]; + float32 im2 = m_ims[i + 1]; + + if (im1 + im2 == 0.0f) + { + continue; + } + + float32 s1 = im1 / (im1 + im2); + float32 s2 = im2 / (im1 + im2); + + p1 -= m_k2 * s1 * (m_Ls[i] - L) * d; + p2 += m_k2 * s2 * (m_Ls[i] - L) * d; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + } +} + +void b2Rope::SetAngle(float32 angle) +{ + int32 count3 = m_count - 2; + for (int32 i = 0; i < count3; ++i) + { + m_as[i] = angle; + } +} + +void b2Rope::SolveC3() +{ + int32 count3 = m_count - 2; + + for (int32 i = 0; i < count3; ++i) + { + b2Vec2 p1 = m_ps[i]; + b2Vec2 p2 = m_ps[i + 1]; + b2Vec2 p3 = m_ps[i + 2]; + + float32 m1 = m_ims[i]; + float32 m2 = m_ims[i + 1]; + float32 m3 = m_ims[i + 2]; + + b2Vec2 d1 = p2 - p1; + b2Vec2 d2 = p3 - p2; + + float32 L1sqr = d1.LengthSquared(); + float32 L2sqr = d2.LengthSquared(); + + if (L1sqr * L2sqr == 0.0f) + { + continue; + } + + float32 a = b2Cross(d1, d2); + float32 b = b2Dot(d1, d2); + + float32 angle = b2Atan2(a, b); + + b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew(); + b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew(); + + b2Vec2 J1 = -Jd1; + b2Vec2 J2 = Jd1 - Jd2; + b2Vec2 J3 = Jd2; + + float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3); + if (mass == 0.0f) + { + continue; + } + + mass = 1.0f / mass; + + float32 C = angle - m_as[i]; + + while (C > b2_pi) + { + angle -= 2 * b2_pi; + C = angle - m_as[i]; + } + + while (C < -b2_pi) + { + angle += 2.0f * b2_pi; + C = angle - m_as[i]; + } + + float32 impulse = - m_k3 * mass * C; + + p1 += (m1 * impulse) * J1; + p2 += (m2 * impulse) * J2; + p3 += (m3 * impulse) * J3; + + m_ps[i] = p1; + m_ps[i + 1] = p2; + m_ps[i + 2] = p3; + } +} + +void b2Rope::Draw(b2Draw* draw) const +{ + b2Color c(0.4f, 0.5f, 0.7f); + + for (int32 i = 0; i < m_count - 1; ++i) + { + draw->DrawSegment(m_ps[i], m_ps[i+1], c); + } +} diff --git a/external/Box2D/Rope/b2Rope.h b/external/Box2D/Rope/b2Rope.h new file mode 100644 index 0000000000..b981dfd6c5 --- /dev/null +++ b/external/Box2D/Rope/b2Rope.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef B2_ROPE_H +#define B2_ROPE_H + +#include + +class b2Draw; + +/// +struct b2RopeDef +{ + b2RopeDef() + { + vertices = NULL; + count = 0; + masses = NULL; + gravity.SetZero(); + damping = 0.1f; + k2 = 0.9f; + k3 = 0.1f; + } + + /// + b2Vec2* vertices; + + /// + int32 count; + + /// + float32* masses; + + /// + b2Vec2 gravity; + + /// + float32 damping; + + /// Stretching stiffness + float32 k2; + + /// Bending stiffness. Values above 0.5 can make the simulation blow up. + float32 k3; +}; + +/// +class b2Rope +{ +public: + b2Rope(); + ~b2Rope(); + + /// + void Initialize(const b2RopeDef* def); + + /// + void Step(float32 timeStep, int32 iterations); + + /// + int32 GetVertexCount() const + { + return m_count; + } + + /// + const b2Vec2* GetVertices() const + { + return m_ps; + } + + /// + void Draw(b2Draw* draw) const; + + /// + void SetAngle(float32 angle); + +private: + + void SolveC2(); + void SolveC3(); + + int32 m_count; + b2Vec2* m_ps; + b2Vec2* m_p0s; + b2Vec2* m_vs; + + float32* m_ims; + + float32* m_Ls; + float32* m_as; + + b2Vec2 m_gravity; + float32 m_damping; + + float32 m_k2; + float32 m_k3; +}; + +#endif diff --git a/external/Box2D/proj.linux/.cproject b/external/Box2D/proj.linux/.cproject new file mode 100644 index 0000000000..5aa092cac3 --- /dev/null +++ b/external/Box2D/proj.linux/.cproject @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Box2D/proj.linux/.project b/external/Box2D/proj.linux/.project new file mode 100644 index 0000000000..164d50f52a --- /dev/null +++ b/external/Box2D/proj.linux/.project @@ -0,0 +1,110 @@ + + + libBox2D + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${workspace_loc:/libBox2D/Debug} + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + Box2D.h + 1 + PARENT-1-PROJECT_LOC/Box2D.h + + + Collision + 2 + PARENT-1-PROJECT_LOC/Collision + + + Common + 2 + PARENT-1-PROJECT_LOC/Common + + + Dynamics + 2 + PARENT-1-PROJECT_LOC/Dynamics + + + Rope + 2 + PARENT-1-PROJECT_LOC/Rope + + + diff --git a/external/Box2D/proj.linux/Makefile b/external/Box2D/proj.linux/Makefile new file mode 100644 index 0000000000..e430bc9883 --- /dev/null +++ b/external/Box2D/proj.linux/Makefile @@ -0,0 +1,72 @@ +TARGET = libbox2d.a + +SOURCES = ../Collision/Shapes/b2ChainShape.cpp \ +../Collision/Shapes/b2CircleShape.cpp \ +../Collision/Shapes/b2EdgeShape.cpp \ +../Collision/Shapes/b2PolygonShape.cpp \ +../Collision/b2BroadPhase.cpp \ +../Collision/b2CollideCircle.cpp \ +../Collision/b2CollideEdge.cpp \ +../Collision/b2CollidePolygon.cpp \ +../Collision/b2Collision.cpp \ +../Collision/b2Distance.cpp \ +../Collision/b2DynamicTree.cpp \ +../Collision/b2TimeOfImpact.cpp \ +../Common/b2BlockAllocator.cpp \ +../Common/b2Draw.cpp \ +../Common/b2Math.cpp \ +../Common/b2Settings.cpp \ +../Common/b2StackAllocator.cpp \ +../Common/b2Timer.cpp \ +../Dynamics/Contacts/b2ChainAndCircleContact.cpp \ +../Dynamics/Contacts/b2ChainAndPolygonContact.cpp \ +../Dynamics/Contacts/b2CircleContact.cpp \ +../Dynamics/Contacts/b2Contact.cpp \ +../Dynamics/Contacts/b2ContactSolver.cpp \ +../Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ +../Dynamics/Contacts/b2EdgeAndPolygonContact.cpp \ +../Dynamics/Contacts/b2PolygonAndCircleContact.cpp \ +../Dynamics/Contacts/b2PolygonContact.cpp \ +../Dynamics/Joints/b2DistanceJoint.cpp \ +../Dynamics/Joints/b2FrictionJoint.cpp \ +../Dynamics/Joints/b2GearJoint.cpp \ +../Dynamics/Joints/b2Joint.cpp \ +../Dynamics/Joints/b2MouseJoint.cpp \ +../Dynamics/Joints/b2PrismaticJoint.cpp \ +../Dynamics/Joints/b2PulleyJoint.cpp \ +../Dynamics/Joints/b2RevoluteJoint.cpp \ +../Dynamics/Joints/b2RopeJoint.cpp \ +../Dynamics/Joints/b2WeldJoint.cpp \ +../Dynamics/Joints/b2WheelJoint.cpp \ +../Dynamics/b2Body.cpp \ +../Dynamics/b2ContactManager.cpp \ +../Dynamics/b2Fixture.cpp \ +../Dynamics/b2Island.cpp \ +../Dynamics/b2World.cpp \ +../Dynamics/b2WorldCallbacks.cpp \ +../Rope/b2Rope.cpp + +include ../../../cocos2dx/proj.linux/cocos2dx.mk + +INCLUDES = -I../.. + +# Cocos2d is not responsible for warnings in external projects +CXXFLAGS += -w + +ifeq ($(DEBUG), 1) +DEFINES = -D_DEBUG +else +DEFINES = +endif + +TARGET := $(LIB_DIR)/$(TARGET) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) $(CORE_MAKEFILE_LIST) + @mkdir -p $(@D) + $(LOG_AR)$(AR) $(ARFLAGS) $(TARGET) $(OBJECTS) + +$(OBJ_DIR)/%.o: ../%.cpp $(CORE_MAKEFILE_LIST) + @mkdir -p $(@D) + $(LOG_CXX)$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ diff --git a/external/Box2D/proj.linux/box2d.prf b/external/Box2D/proj.linux/box2d.prf new file mode 100644 index 0000000000..434ad88406 --- /dev/null +++ b/external/Box2D/proj.linux/box2d.prf @@ -0,0 +1,19 @@ +################################################################################ +# Do not include this file in your project: see cocos2dx.pri. +################################################################################ + +linux { + # We will compile box2d on demand using Makefile. + build_box2d.name = Build box2d static library + build_box2d.input = $$PWD/Makefile + build_box2d.output = $$CC_LIBRARY_DIR/libbox2d.a + build_box2d.target = $$CC_LIBRARY_DIR/libbox2d.a + build_box2d.CONFIG = no_link target_predeps + build_box2d.commands = cd $$PWD && make $$CC_MAKE_FLAGS + + QMAKE_EXTRA_COMPILERS += build_box2d + QMAKE_EXTRA_TARGETS += build_box2d + + PRE_TARGETDEPS += $$CC_LIBRARY_DIR/libbox2d.a + LIBS += -Wl,-Bstatic -lbox2d -Wl,-Bdynamic +} diff --git a/external/Box2D/proj.win32/Box2D.vcxproj b/external/Box2D/proj.win32/Box2D.vcxproj new file mode 100644 index 0000000000..cd4bd2086c --- /dev/null +++ b/external/Box2D/proj.win32/Box2D.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + libBox2D + {929480E7-23C0-4DF6-8456-096D71547116} + Box2D.win32 + Win32Proj + + + + StaticLibrary + Unicode + v100 + v110 + v110_xp + + + StaticLibrary + Unicode + v100 + v110 + v110_xp + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration).win32\ + $(Configuration).win32\ + $(SolutionDir)$(Configuration).win32\ + $(Configuration).win32\ + AllRules.ruleset + + + AllRules.ruleset + + + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath) + + + + Disabled + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + true + + + $(OutDir)$(ProjectName).lib + + + + + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;../../;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + true + + + $(OutDir)$(ProjectName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Box2D/proj.win32/Box2D.vcxproj.filters b/external/Box2D/proj.win32/Box2D.vcxproj.filters new file mode 100644 index 0000000000..e810cbb0cf --- /dev/null +++ b/external/Box2D/proj.win32/Box2D.vcxproj.filters @@ -0,0 +1,301 @@ + + + + + {bdf099c5-cc32-468b-b53f-ec010d7f823f} + + + {92792f88-4e5c-46ee-8d87-002f3b2297ae} + + + {f41a6fa6-5ac1-4514-9ac0-6f3a38f35b4d} + + + {0b56913a-34b7-410a-b386-869d6f7a20be} + + + {f0e7b230-79cc-49b8-9ed7-9dbfa062f2a4} + + + {932f2008-afbe-42f5-993d-a1df0ec67756} + + + {f8937e09-93a4-49fa-8f3e-dfc36da764df} + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Collision\Shapes + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Common + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Contacts + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Dynamics\Joints + + + Rope + + + + \ No newline at end of file diff --git a/external/Box2D/proj.win32/Box2D.vcxproj.user b/external/Box2D/proj.win32/Box2D.vcxproj.user new file mode 100644 index 0000000000..ace9a86acb --- /dev/null +++ b/external/Box2D/proj.win32/Box2D.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 7de6646213901c3d887923e1969cb0630f4e028e Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 12 Oct 2013 14:56:40 +0800 Subject: [PATCH 113/116] Don't ignore (D|d)ebugXXX folders or files. And move scripting/javascript/bindings/js to 'scripting/javascript/script/' folder. --- .gitignore | 4 ++-- .../{bindings/js => script}/debugger/DevToolsUtils.js | 0 .../javascript/{bindings/js => script}/debugger/README.md | 0 .../{bindings/js => script}/debugger/actors/root.js | 0 .../{bindings/js => script}/debugger/actors/script.js | 0 .../{bindings/js => script}/debugger/core/promise.js | 0 .../javascript/{bindings/js => script}/debugger/main.js | 0 .../javascript/{bindings/js => script}/debugger/transport.js | 0 cocos/scripting/javascript/{bindings/js => script}/jsb.js | 0 .../javascript/{bindings/js => script}/jsb_chipmunk.js | 0 .../{bindings/js => script}/jsb_chipmunk_constants.js | 0 .../javascript/{bindings/js => script}/jsb_cocos2d.js | 0 .../{bindings/js => script}/jsb_cocos2d_constants.js | 0 .../{bindings/js => script}/jsb_cocos2d_extension.js | 0 .../javascript/{bindings/js => script}/jsb_cocosbuilder.js | 0 .../javascript/{bindings/js => script}/jsb_debugger.js | 0 .../javascript/{bindings/js => script}/jsb_deprecated.js | 0 .../javascript/{bindings/js => script}/jsb_opengl.js | 0 .../{bindings/js => script}/jsb_opengl_constants.js | 0 cocos/scripting/javascript/{bindings/js => script}/jsb_sys.js | 0 20 files changed, 2 insertions(+), 2 deletions(-) rename cocos/scripting/javascript/{bindings/js => script}/debugger/DevToolsUtils.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/README.md (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/actors/root.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/actors/script.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/core/promise.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/main.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/debugger/transport.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_chipmunk.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_chipmunk_constants.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_cocos2d.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_cocos2d_constants.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_cocos2d_extension.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_cocosbuilder.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_debugger.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_deprecated.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_opengl.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_opengl_constants.js (100%) rename cocos/scripting/javascript/{bindings/js => script}/jsb_sys.js (100%) diff --git a/.gitignore b/.gitignore index 14845a8164..d6bae12eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,11 +21,11 @@ Thumbs.db *.ilk *.log [Bb]in -[Dd]ebug*/ +[Dd]ebug/ *.sbr *.sdf obj/ -[Rr]elease*/ +[Rr]elease/ _ReSharper*/ [Tt]est[Rr]esult* ipch/ diff --git a/cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js b/cocos/scripting/javascript/script/debugger/DevToolsUtils.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/DevToolsUtils.js rename to cocos/scripting/javascript/script/debugger/DevToolsUtils.js diff --git a/cocos/scripting/javascript/bindings/js/debugger/README.md b/cocos/scripting/javascript/script/debugger/README.md similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/README.md rename to cocos/scripting/javascript/script/debugger/README.md diff --git a/cocos/scripting/javascript/bindings/js/debugger/actors/root.js b/cocos/scripting/javascript/script/debugger/actors/root.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/actors/root.js rename to cocos/scripting/javascript/script/debugger/actors/root.js diff --git a/cocos/scripting/javascript/bindings/js/debugger/actors/script.js b/cocos/scripting/javascript/script/debugger/actors/script.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/actors/script.js rename to cocos/scripting/javascript/script/debugger/actors/script.js diff --git a/cocos/scripting/javascript/bindings/js/debugger/core/promise.js b/cocos/scripting/javascript/script/debugger/core/promise.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/core/promise.js rename to cocos/scripting/javascript/script/debugger/core/promise.js diff --git a/cocos/scripting/javascript/bindings/js/debugger/main.js b/cocos/scripting/javascript/script/debugger/main.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/main.js rename to cocos/scripting/javascript/script/debugger/main.js diff --git a/cocos/scripting/javascript/bindings/js/debugger/transport.js b/cocos/scripting/javascript/script/debugger/transport.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/debugger/transport.js rename to cocos/scripting/javascript/script/debugger/transport.js diff --git a/cocos/scripting/javascript/bindings/js/jsb.js b/cocos/scripting/javascript/script/jsb.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb.js rename to cocos/scripting/javascript/script/jsb.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_chipmunk.js b/cocos/scripting/javascript/script/jsb_chipmunk.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_chipmunk.js rename to cocos/scripting/javascript/script/jsb_chipmunk.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_chipmunk_constants.js b/cocos/scripting/javascript/script/jsb_chipmunk_constants.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_chipmunk_constants.js rename to cocos/scripting/javascript/script/jsb_chipmunk_constants.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_cocos2d.js b/cocos/scripting/javascript/script/jsb_cocos2d.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_cocos2d.js rename to cocos/scripting/javascript/script/jsb_cocos2d.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_cocos2d_constants.js b/cocos/scripting/javascript/script/jsb_cocos2d_constants.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_cocos2d_constants.js rename to cocos/scripting/javascript/script/jsb_cocos2d_constants.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_cocos2d_extension.js b/cocos/scripting/javascript/script/jsb_cocos2d_extension.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_cocos2d_extension.js rename to cocos/scripting/javascript/script/jsb_cocos2d_extension.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_cocosbuilder.js b/cocos/scripting/javascript/script/jsb_cocosbuilder.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_cocosbuilder.js rename to cocos/scripting/javascript/script/jsb_cocosbuilder.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_debugger.js b/cocos/scripting/javascript/script/jsb_debugger.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_debugger.js rename to cocos/scripting/javascript/script/jsb_debugger.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_deprecated.js b/cocos/scripting/javascript/script/jsb_deprecated.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_deprecated.js rename to cocos/scripting/javascript/script/jsb_deprecated.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_opengl.js b/cocos/scripting/javascript/script/jsb_opengl.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_opengl.js rename to cocos/scripting/javascript/script/jsb_opengl.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_opengl_constants.js b/cocos/scripting/javascript/script/jsb_opengl_constants.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_opengl_constants.js rename to cocos/scripting/javascript/script/jsb_opengl_constants.js diff --git a/cocos/scripting/javascript/bindings/js/jsb_sys.js b/cocos/scripting/javascript/script/jsb_sys.js similarity index 100% rename from cocos/scripting/javascript/bindings/js/jsb_sys.js rename to cocos/scripting/javascript/script/jsb_sys.js From f6275667bfbb3990f8728a6d6113ad60b9d1a220 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 12 Oct 2013 15:02:28 +0800 Subject: [PATCH 114/116] Removing unused ios projects. --- .../bindings/proj.ios/jsbindings-Prefix.pch | 7 - .../jsbindings.xcodeproj/project.pbxproj | 673 ------------------ .../bindings/proj.mac/jsbindings-Prefix.pch | 7 - .../jsbindings.xcodeproj/project.pbxproj | 651 ----------------- .../luabindings.xcodeproj/project.pbxproj | 453 ------------ .../HelloLua.xcodeproj/project.pbxproj | 491 ------------- .../TestLua.xcodeproj/project.pbxproj | 573 --------------- 7 files changed, 2855 deletions(-) delete mode 100644 cocos/scripting/javascript/bindings/proj.ios/jsbindings-Prefix.pch delete mode 100644 cocos/scripting/javascript/bindings/proj.ios/jsbindings.xcodeproj/project.pbxproj delete mode 100644 cocos/scripting/javascript/bindings/proj.mac/jsbindings-Prefix.pch delete mode 100644 cocos/scripting/javascript/bindings/proj.mac/jsbindings.xcodeproj/project.pbxproj delete mode 100644 cocos/scripting/lua/proj.ios/luabindings.xcodeproj/project.pbxproj delete mode 100644 samples/Lua/HelloLua/proj.ios/HelloLua.xcodeproj/project.pbxproj delete mode 100644 samples/Lua/TestLua/proj.ios/TestLua.xcodeproj/project.pbxproj diff --git a/cocos/scripting/javascript/bindings/proj.ios/jsbindings-Prefix.pch b/cocos/scripting/javascript/bindings/proj.ios/jsbindings-Prefix.pch deleted file mode 100644 index af8c4a19d5..0000000000 --- a/cocos/scripting/javascript/bindings/proj.ios/jsbindings-Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'jsbindings' target in the 'jsbindings' project -// - -#ifdef __OBJC__ - #import -#endif diff --git a/cocos/scripting/javascript/bindings/proj.ios/jsbindings.xcodeproj/project.pbxproj b/cocos/scripting/javascript/bindings/proj.ios/jsbindings.xcodeproj/project.pbxproj deleted file mode 100644 index cb9d02ae01..0000000000 --- a/cocos/scripting/javascript/bindings/proj.ios/jsbindings.xcodeproj/project.pbxproj +++ /dev/null @@ -1,673 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1A0C0E8B1778088700838530 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C0E8A1778088700838530 /* Foundation.framework */; }; - 1A0C0EDA1778095000838530 /* cocos2d_specifics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */; }; - 1A0C0EDB1778095000838530 /* cocosjs_manual_conversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */; }; - 1A0C0EDC1778095000838530 /* jsb_cocos2dx_auto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */; }; - 1A0C0EEC1778095000838530 /* js_bindings_ccbreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */; }; - 1A0C0EED1778095000838530 /* js_bindings_chipmunk_auto_classes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */; }; - 1A0C0EEE1778095000838530 /* js_bindings_chipmunk_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */; }; - 1A0C0EEF1778095000838530 /* js_bindings_chipmunk_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */; }; - 1A0C0EF01778095000838530 /* js_bindings_chipmunk_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */; }; - 1A0C0EF11778095000838530 /* js_bindings_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */; }; - 1A0C0EF21778095000838530 /* js_bindings_opengl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */; }; - 1A0C0EF31778095000838530 /* js_bindings_system_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */; }; - 1A0C0EF41778095000838530 /* js_bindings_system_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */; }; - 1A0C0EF51778095000838530 /* js_manual_conversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */; }; - 1A0C0EF61778095000838530 /* jsb_cocos2dx_extension_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */; }; - 1A0C0EF71778095000838530 /* jsb_opengl_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */; }; - 1A0C0EF81778095000838530 /* jsb_opengl_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */; }; - 1A0C0EF91778095000838530 /* jsb_opengl_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */; }; - 1A0C0EFA1778095000838530 /* jsb_websocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED31778095000838530 /* jsb_websocket.cpp */; }; - 1A0C0EFB1778095000838530 /* ScriptingCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED51778095000838530 /* ScriptingCore.cpp */; }; - 1A0C0EFC1778095000838530 /* XMLHTTPRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */; }; - 1A0C0F4917780A9700838530 /* libjs_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C0F4817780A9700838530 /* libjs_static.a */; }; - 1A6E46D51778162E0055514D /* jsb_cocos2dx_extension_auto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 1A0C0E851778088700838530 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1A0C0E871778088700838530 /* libjsbindings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsbindings.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A0C0E8A1778088700838530 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cocos2d_specifics.cpp; path = ../cocos2d_specifics.cpp; sourceTree = ""; }; - 1A0C0E9A1778095000838530 /* cocos2d_specifics.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = cocos2d_specifics.hpp; path = ../cocos2d_specifics.hpp; sourceTree = ""; }; - 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cocosjs_manual_conversions.cpp; path = ../cocosjs_manual_conversions.cpp; sourceTree = ""; }; - 1A0C0E9C1778095000838530 /* cocosjs_manual_conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocosjs_manual_conversions.h; path = ../cocosjs_manual_conversions.h; sourceTree = ""; }; - 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsb_cocos2dx_auto.cpp; sourceTree = ""; }; - 1A0C0E9F1778095000838530 /* jsb_cocos2dx_auto.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsb_cocos2dx_auto.hpp; sourceTree = ""; }; - 1A0C0EA01778095000838530 /* jsb_cocos2dx_auto_api.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2dx_auto_api.js; sourceTree = ""; }; - 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsb_cocos2dx_extension_auto.cpp; sourceTree = ""; }; - 1A0C0EA21778095000838530 /* jsb_cocos2dx_extension_auto.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsb_cocos2dx_extension_auto.hpp; sourceTree = ""; }; - 1A0C0EA31778095000838530 /* jsb_cocos2dx_extension_auto_api.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2dx_extension_auto_api.js; sourceTree = ""; }; - 1A0C0EA41778095000838530 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 1A0C0EA61778095000838530 /* jsb.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb.js; sourceTree = ""; }; - 1A0C0EA71778095000838530 /* jsb_chipmunk.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_chipmunk.js; sourceTree = ""; }; - 1A0C0EA81778095000838530 /* jsb_chipmunk_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_chipmunk_constants.js; sourceTree = ""; }; - 1A0C0EA91778095000838530 /* jsb_cocos2d.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d.js; sourceTree = ""; }; - 1A0C0EAA1778095000838530 /* jsb_cocos2d_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d_constants.js; sourceTree = ""; }; - 1A0C0EAB1778095000838530 /* jsb_cocos2d_extension.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d_extension.js; sourceTree = ""; }; - 1A0C0EAC1778095000838530 /* jsb_cocosbuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocosbuilder.js; sourceTree = ""; }; - 1A0C0EAD1778095000838530 /* jsb_debugger.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_debugger.js; sourceTree = ""; }; - 1A0C0EAE1778095000838530 /* jsb_opengl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_opengl.js; sourceTree = ""; }; - 1A0C0EAF1778095000838530 /* jsb_opengl_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_opengl_constants.js; sourceTree = ""; }; - 1A0C0EB01778095000838530 /* jsb_sys.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_sys.js; sourceTree = ""; }; - 1A0C0EB11778095000838530 /* main.debug.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = main.debug.js; sourceTree = ""; }; - 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_ccbreader.cpp; path = ../js_bindings_ccbreader.cpp; sourceTree = ""; }; - 1A0C0EB31778095000838530 /* js_bindings_ccbreader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_ccbreader.h; path = ../js_bindings_ccbreader.h; sourceTree = ""; }; - 1A0C0EB41778095000838530 /* js_bindings_chipmunk_auto_classes_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_auto_classes_registration.h; path = ../js_bindings_chipmunk_auto_classes_registration.h; sourceTree = ""; }; - 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_auto_classes.cpp; path = ../js_bindings_chipmunk_auto_classes.cpp; sourceTree = ""; }; - 1A0C0EB61778095000838530 /* js_bindings_chipmunk_auto_classes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_auto_classes.h; path = ../js_bindings_chipmunk_auto_classes.h; sourceTree = ""; }; - 1A0C0EB71778095000838530 /* js_bindings_chipmunk_functions_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_functions_registration.h; path = ../js_bindings_chipmunk_functions_registration.h; sourceTree = ""; }; - 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_functions.cpp; path = ../js_bindings_chipmunk_functions.cpp; sourceTree = ""; }; - 1A0C0EB91778095000838530 /* js_bindings_chipmunk_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_functions.h; path = ../js_bindings_chipmunk_functions.h; sourceTree = ""; }; - 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_manual.cpp; path = ../js_bindings_chipmunk_manual.cpp; sourceTree = ""; }; - 1A0C0EBB1778095000838530 /* js_bindings_chipmunk_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_manual.h; path = ../js_bindings_chipmunk_manual.h; sourceTree = ""; }; - 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_registration.cpp; path = ../js_bindings_chipmunk_registration.cpp; sourceTree = ""; }; - 1A0C0EBD1778095000838530 /* js_bindings_chipmunk_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_registration.h; path = ../js_bindings_chipmunk_registration.h; sourceTree = ""; }; - 1A0C0EBE1778095000838530 /* js_bindings_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_config.h; path = ../js_bindings_config.h; sourceTree = ""; }; - 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_core.cpp; path = ../js_bindings_core.cpp; sourceTree = ""; }; - 1A0C0EC01778095000838530 /* js_bindings_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_core.h; path = ../js_bindings_core.h; sourceTree = ""; }; - 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_opengl.cpp; path = ../js_bindings_opengl.cpp; sourceTree = ""; }; - 1A0C0EC21778095000838530 /* js_bindings_opengl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_opengl.h; path = ../js_bindings_opengl.h; sourceTree = ""; }; - 1A0C0EC31778095000838530 /* js_bindings_system_functions_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_functions_registration.h; path = ../js_bindings_system_functions_registration.h; sourceTree = ""; }; - 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_system_functions.cpp; path = ../js_bindings_system_functions.cpp; sourceTree = ""; }; - 1A0C0EC51778095000838530 /* js_bindings_system_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_functions.h; path = ../js_bindings_system_functions.h; sourceTree = ""; }; - 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_system_registration.cpp; path = ../js_bindings_system_registration.cpp; sourceTree = ""; }; - 1A0C0EC71778095000838530 /* js_bindings_system_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_registration.h; path = ../js_bindings_system_registration.h; sourceTree = ""; }; - 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_manual_conversions.cpp; path = ../js_manual_conversions.cpp; sourceTree = ""; }; - 1A0C0EC91778095000838530 /* js_manual_conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_manual_conversions.h; path = ../js_manual_conversions.h; sourceTree = ""; }; - 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_cocos2dx_extension_manual.cpp; path = ../jsb_cocos2dx_extension_manual.cpp; sourceTree = ""; }; - 1A0C0ECB1778095000838530 /* jsb_cocos2dx_extension_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_cocos2dx_extension_manual.h; path = ../jsb_cocos2dx_extension_manual.h; sourceTree = ""; }; - 1A0C0ECC1778095000838530 /* jsb_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_helper.h; path = ../jsb_helper.h; sourceTree = ""; }; - 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_functions.cpp; path = ../jsb_opengl_functions.cpp; sourceTree = ""; }; - 1A0C0ECE1778095000838530 /* jsb_opengl_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_functions.h; path = ../jsb_opengl_functions.h; sourceTree = ""; }; - 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_manual.cpp; path = ../jsb_opengl_manual.cpp; sourceTree = ""; }; - 1A0C0ED01778095000838530 /* jsb_opengl_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_manual.h; path = ../jsb_opengl_manual.h; sourceTree = ""; }; - 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_registration.cpp; path = ../jsb_opengl_registration.cpp; sourceTree = ""; }; - 1A0C0ED21778095000838530 /* jsb_opengl_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_registration.h; path = ../jsb_opengl_registration.h; sourceTree = ""; }; - 1A0C0ED31778095000838530 /* jsb_websocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_websocket.cpp; path = ../jsb_websocket.cpp; sourceTree = ""; }; - 1A0C0ED41778095000838530 /* jsb_websocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_websocket.h; path = ../jsb_websocket.h; sourceTree = ""; }; - 1A0C0ED51778095000838530 /* ScriptingCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptingCore.cpp; path = ../ScriptingCore.cpp; sourceTree = ""; }; - 1A0C0ED61778095000838530 /* ScriptingCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptingCore.h; path = ../ScriptingCore.h; sourceTree = ""; }; - 1A0C0ED71778095000838530 /* spidermonkey_specifics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spidermonkey_specifics.h; path = ../spidermonkey_specifics.h; sourceTree = ""; }; - 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XMLHTTPRequest.cpp; path = ../XMLHTTPRequest.cpp; sourceTree = ""; }; - 1A0C0ED91778095000838530 /* XMLHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMLHTTPRequest.h; path = ../XMLHTTPRequest.h; sourceTree = ""; }; - 1A0C0F0017780A9700838530 /* BitArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitArray.h; sourceTree = ""; }; - 1A0C0F0217780A9700838530 /* Root.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Root.h; sourceTree = ""; }; - 1A0C0F0417780A9700838530 /* Anchor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Anchor.h; sourceTree = ""; }; - 1A0C0F0517780A9700838530 /* CharacterEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterEncoding.h; sourceTree = ""; }; - 1A0C0F0617780A9700838530 /* GCAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCAPI.h; sourceTree = ""; }; - 1A0C0F0717780A9700838530 /* HashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashTable.h; sourceTree = ""; }; - 1A0C0F0817780A9700838530 /* HeapAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapAPI.h; sourceTree = ""; }; - 1A0C0F0917780A9700838530 /* LegacyIntTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyIntTypes.h; sourceTree = ""; }; - 1A0C0F0A17780A9700838530 /* MemoryMetrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryMetrics.h; sourceTree = ""; }; - 1A0C0F0B17780A9700838530 /* PropertyKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyKey.h; sourceTree = ""; }; - 1A0C0F0C17780A9700838530 /* RequiredDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequiredDefines.h; sourceTree = ""; }; - 1A0C0F0D17780A9700838530 /* TemplateLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateLib.h; sourceTree = ""; }; - 1A0C0F0E17780A9700838530 /* Utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utility.h; sourceTree = ""; }; - 1A0C0F0F17780A9700838530 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Value.h; sourceTree = ""; }; - 1A0C0F1017780A9700838530 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = ""; }; - 1A0C0F1117780A9700838530 /* js-config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "js-config.h"; sourceTree = ""; }; - 1A0C0F1217780A9700838530 /* js.msg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = js.msg; sourceTree = ""; }; - 1A0C0F1317780A9700838530 /* jsalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsalloc.h; sourceTree = ""; }; - 1A0C0F1417780A9700838530 /* jsapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsapi.h; sourceTree = ""; }; - 1A0C0F1517780A9700838530 /* jsclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsclass.h; sourceTree = ""; }; - 1A0C0F1617780A9700838530 /* jsclist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsclist.h; sourceTree = ""; }; - 1A0C0F1717780A9700838530 /* jscpucfg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jscpucfg.h; sourceTree = ""; }; - 1A0C0F1817780A9700838530 /* jsdbgapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsdbgapi.h; sourceTree = ""; }; - 1A0C0F1917780A9700838530 /* jsdhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsdhash.h; sourceTree = ""; }; - 1A0C0F1A17780A9700838530 /* jsfriendapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsfriendapi.h; sourceTree = ""; }; - 1A0C0F1B17780A9700838530 /* jslock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jslock.h; sourceTree = ""; }; - 1A0C0F1C17780A9700838530 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = ""; }; - 1A0C0F1D17780A9700838530 /* jsperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsperf.h; sourceTree = ""; }; - 1A0C0F1E17780A9700838530 /* jsprf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprf.h; sourceTree = ""; }; - 1A0C0F1F17780A9700838530 /* jsprototypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprototypes.h; sourceTree = ""; }; - 1A0C0F2017780A9700838530 /* jsproxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsproxy.h; sourceTree = ""; }; - 1A0C0F2117780A9700838530 /* jsprvtd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprvtd.h; sourceTree = ""; }; - 1A0C0F2217780A9700838530 /* jspubtd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jspubtd.h; sourceTree = ""; }; - 1A0C0F2317780A9700838530 /* jstypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jstypes.h; sourceTree = ""; }; - 1A0C0F2417780A9700838530 /* jsutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsutil.h; sourceTree = ""; }; - 1A0C0F2517780A9700838530 /* jsversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsversion.h; sourceTree = ""; }; - 1A0C0F2617780A9700838530 /* jswrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jswrapper.h; sourceTree = ""; }; - 1A0C0F2817780A9700838530 /* Assertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Assertions.h; sourceTree = ""; }; - 1A0C0F2917780A9700838530 /* Attributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attributes.h; sourceTree = ""; }; - 1A0C0F2A17780A9700838530 /* BloomFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BloomFilter.h; sourceTree = ""; }; - 1A0C0F2B17780A9700838530 /* Char16.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Char16.h; sourceTree = ""; }; - 1A0C0F2C17780A9700838530 /* CheckedInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckedInt.h; sourceTree = ""; }; - 1A0C0F2D17780A9700838530 /* Compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Compiler.h; sourceTree = ""; }; - 1A0C0F2E17780A9700838530 /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; - 1A0C0F2F17780A9700838530 /* DebugOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugOnly.h; sourceTree = ""; }; - 1A0C0F3017780A9700838530 /* EnumSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumSet.h; sourceTree = ""; }; - 1A0C0F3117780A9700838530 /* FloatingPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatingPoint.h; sourceTree = ""; }; - 1A0C0F3217780A9700838530 /* GuardObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuardObjects.h; sourceTree = ""; }; - 1A0C0F3317780A9700838530 /* HashFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashFunctions.h; sourceTree = ""; }; - 1A0C0F3417780A9700838530 /* Likely.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Likely.h; sourceTree = ""; }; - 1A0C0F3517780A9700838530 /* LinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkedList.h; sourceTree = ""; }; - 1A0C0F3617780A9700838530 /* MathAlgorithms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathAlgorithms.h; sourceTree = ""; }; - 1A0C0F3717780A9700838530 /* MemoryChecking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryChecking.h; sourceTree = ""; }; - 1A0C0F3817780A9700838530 /* MSStdInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSStdInt.h; sourceTree = ""; }; - 1A0C0F3917780A9700838530 /* NullPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullPtr.h; sourceTree = ""; }; - 1A0C0F3A17780A9700838530 /* Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Range.h; sourceTree = ""; }; - 1A0C0F3B17780A9700838530 /* RangedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangedPtr.h; sourceTree = ""; }; - 1A0C0F3C17780A9700838530 /* RefPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefPtr.h; sourceTree = ""; }; - 1A0C0F3D17780A9700838530 /* Scoped.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scoped.h; sourceTree = ""; }; - 1A0C0F3E17780A9700838530 /* SHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHA1.h; sourceTree = ""; }; - 1A0C0F3F17780A9700838530 /* SplayTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SplayTree.h; sourceTree = ""; }; - 1A0C0F4017780A9700838530 /* StandardInteger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StandardInteger.h; sourceTree = ""; }; - 1A0C0F4117780A9700838530 /* ThreadLocal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadLocal.h; sourceTree = ""; }; - 1A0C0F4217780A9700838530 /* TypedEnum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedEnum.h; sourceTree = ""; }; - 1A0C0F4317780A9700838530 /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = ""; }; - 1A0C0F4417780A9700838530 /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = ""; }; - 1A0C0F4517780A9700838530 /* Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Util.h; sourceTree = ""; }; - 1A0C0F4617780A9700838530 /* WeakPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakPtr.h; sourceTree = ""; }; - 1A0C0F4817780A9700838530 /* libjs_static.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libjs_static.a; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1A0C0E841778088700838530 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A0C0E8B1778088700838530 /* Foundation.framework in Frameworks */, - 1A0C0F4917780A9700838530 /* libjs_static.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1A0C0E7E1778088700838530 = { - isa = PBXGroup; - children = ( - 1A0C0E981778093E00838530 /* bindings */, - 1A0C0E891778088700838530 /* Frameworks */, - 1A0C0E881778088700838530 /* Products */, - ); - sourceTree = ""; - }; - 1A0C0E881778088700838530 /* Products */ = { - isa = PBXGroup; - children = ( - 1A0C0E871778088700838530 /* libjsbindings.a */, - ); - name = Products; - sourceTree = ""; - }; - 1A0C0E891778088700838530 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1A0C0EFD17780A9700838530 /* spidermonkey-ios */, - 1A0C0E8A1778088700838530 /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 1A0C0E981778093E00838530 /* bindings */ = { - isa = PBXGroup; - children = ( - 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */, - 1A0C0E9A1778095000838530 /* cocos2d_specifics.hpp */, - 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */, - 1A0C0E9C1778095000838530 /* cocosjs_manual_conversions.h */, - 1A0C0E9D1778095000838530 /* generated */, - 1A0C0EA51778095000838530 /* js */, - 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */, - 1A0C0EB31778095000838530 /* js_bindings_ccbreader.h */, - 1A0C0EB41778095000838530 /* js_bindings_chipmunk_auto_classes_registration.h */, - 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */, - 1A0C0EB61778095000838530 /* js_bindings_chipmunk_auto_classes.h */, - 1A0C0EB71778095000838530 /* js_bindings_chipmunk_functions_registration.h */, - 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */, - 1A0C0EB91778095000838530 /* js_bindings_chipmunk_functions.h */, - 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */, - 1A0C0EBB1778095000838530 /* js_bindings_chipmunk_manual.h */, - 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */, - 1A0C0EBD1778095000838530 /* js_bindings_chipmunk_registration.h */, - 1A0C0EBE1778095000838530 /* js_bindings_config.h */, - 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */, - 1A0C0EC01778095000838530 /* js_bindings_core.h */, - 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */, - 1A0C0EC21778095000838530 /* js_bindings_opengl.h */, - 1A0C0EC31778095000838530 /* js_bindings_system_functions_registration.h */, - 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */, - 1A0C0EC51778095000838530 /* js_bindings_system_functions.h */, - 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */, - 1A0C0EC71778095000838530 /* js_bindings_system_registration.h */, - 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */, - 1A0C0EC91778095000838530 /* js_manual_conversions.h */, - 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */, - 1A0C0ECB1778095000838530 /* jsb_cocos2dx_extension_manual.h */, - 1A0C0ECC1778095000838530 /* jsb_helper.h */, - 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */, - 1A0C0ECE1778095000838530 /* jsb_opengl_functions.h */, - 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */, - 1A0C0ED01778095000838530 /* jsb_opengl_manual.h */, - 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */, - 1A0C0ED21778095000838530 /* jsb_opengl_registration.h */, - 1A0C0ED31778095000838530 /* jsb_websocket.cpp */, - 1A0C0ED41778095000838530 /* jsb_websocket.h */, - 1A0C0ED51778095000838530 /* ScriptingCore.cpp */, - 1A0C0ED61778095000838530 /* ScriptingCore.h */, - 1A0C0ED71778095000838530 /* spidermonkey_specifics.h */, - 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */, - 1A0C0ED91778095000838530 /* XMLHTTPRequest.h */, - ); - name = bindings; - sourceTree = ""; - }; - 1A0C0E9D1778095000838530 /* generated */ = { - isa = PBXGroup; - children = ( - 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */, - 1A0C0E9F1778095000838530 /* jsb_cocos2dx_auto.hpp */, - 1A0C0EA01778095000838530 /* jsb_cocos2dx_auto_api.js */, - 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */, - 1A0C0EA21778095000838530 /* jsb_cocos2dx_extension_auto.hpp */, - 1A0C0EA31778095000838530 /* jsb_cocos2dx_extension_auto_api.js */, - 1A0C0EA41778095000838530 /* README */, - ); - name = generated; - path = ../generated; - sourceTree = ""; - }; - 1A0C0EA51778095000838530 /* js */ = { - isa = PBXGroup; - children = ( - 1A0C0EA61778095000838530 /* jsb.js */, - 1A0C0EA71778095000838530 /* jsb_chipmunk.js */, - 1A0C0EA81778095000838530 /* jsb_chipmunk_constants.js */, - 1A0C0EA91778095000838530 /* jsb_cocos2d.js */, - 1A0C0EAA1778095000838530 /* jsb_cocos2d_constants.js */, - 1A0C0EAB1778095000838530 /* jsb_cocos2d_extension.js */, - 1A0C0EAC1778095000838530 /* jsb_cocosbuilder.js */, - 1A0C0EAD1778095000838530 /* jsb_debugger.js */, - 1A0C0EAE1778095000838530 /* jsb_opengl.js */, - 1A0C0EAF1778095000838530 /* jsb_opengl_constants.js */, - 1A0C0EB01778095000838530 /* jsb_sys.js */, - 1A0C0EB11778095000838530 /* main.debug.js */, - ); - name = js; - path = ../js; - sourceTree = ""; - }; - 1A0C0EFD17780A9700838530 /* spidermonkey-ios */ = { - isa = PBXGroup; - children = ( - 1A0C0EFE17780A9700838530 /* include */, - 1A0C0F4717780A9700838530 /* lib */, - ); - name = "spidermonkey-ios"; - path = "../../spidermonkey-ios"; - sourceTree = ""; - }; - 1A0C0EFE17780A9700838530 /* include */ = { - isa = PBXGroup; - children = ( - 1A0C0EFF17780A9700838530 /* ds */, - 1A0C0F0117780A9700838530 /* gc */, - 1A0C0F0317780A9700838530 /* js */, - 1A0C0F1117780A9700838530 /* js-config.h */, - 1A0C0F1217780A9700838530 /* js.msg */, - 1A0C0F1317780A9700838530 /* jsalloc.h */, - 1A0C0F1417780A9700838530 /* jsapi.h */, - 1A0C0F1517780A9700838530 /* jsclass.h */, - 1A0C0F1617780A9700838530 /* jsclist.h */, - 1A0C0F1717780A9700838530 /* jscpucfg.h */, - 1A0C0F1817780A9700838530 /* jsdbgapi.h */, - 1A0C0F1917780A9700838530 /* jsdhash.h */, - 1A0C0F1A17780A9700838530 /* jsfriendapi.h */, - 1A0C0F1B17780A9700838530 /* jslock.h */, - 1A0C0F1C17780A9700838530 /* json.h */, - 1A0C0F1D17780A9700838530 /* jsperf.h */, - 1A0C0F1E17780A9700838530 /* jsprf.h */, - 1A0C0F1F17780A9700838530 /* jsprototypes.h */, - 1A0C0F2017780A9700838530 /* jsproxy.h */, - 1A0C0F2117780A9700838530 /* jsprvtd.h */, - 1A0C0F2217780A9700838530 /* jspubtd.h */, - 1A0C0F2317780A9700838530 /* jstypes.h */, - 1A0C0F2417780A9700838530 /* jsutil.h */, - 1A0C0F2517780A9700838530 /* jsversion.h */, - 1A0C0F2617780A9700838530 /* jswrapper.h */, - 1A0C0F2717780A9700838530 /* mozilla */, - ); - path = include; - sourceTree = ""; - }; - 1A0C0EFF17780A9700838530 /* ds */ = { - isa = PBXGroup; - children = ( - 1A0C0F0017780A9700838530 /* BitArray.h */, - ); - path = ds; - sourceTree = ""; - }; - 1A0C0F0117780A9700838530 /* gc */ = { - isa = PBXGroup; - children = ( - 1A0C0F0217780A9700838530 /* Root.h */, - ); - path = gc; - sourceTree = ""; - }; - 1A0C0F0317780A9700838530 /* js */ = { - isa = PBXGroup; - children = ( - 1A0C0F0417780A9700838530 /* Anchor.h */, - 1A0C0F0517780A9700838530 /* CharacterEncoding.h */, - 1A0C0F0617780A9700838530 /* GCAPI.h */, - 1A0C0F0717780A9700838530 /* HashTable.h */, - 1A0C0F0817780A9700838530 /* HeapAPI.h */, - 1A0C0F0917780A9700838530 /* LegacyIntTypes.h */, - 1A0C0F0A17780A9700838530 /* MemoryMetrics.h */, - 1A0C0F0B17780A9700838530 /* PropertyKey.h */, - 1A0C0F0C17780A9700838530 /* RequiredDefines.h */, - 1A0C0F0D17780A9700838530 /* TemplateLib.h */, - 1A0C0F0E17780A9700838530 /* Utility.h */, - 1A0C0F0F17780A9700838530 /* Value.h */, - 1A0C0F1017780A9700838530 /* Vector.h */, - ); - path = js; - sourceTree = ""; - }; - 1A0C0F2717780A9700838530 /* mozilla */ = { - isa = PBXGroup; - children = ( - 1A0C0F2817780A9700838530 /* Assertions.h */, - 1A0C0F2917780A9700838530 /* Attributes.h */, - 1A0C0F2A17780A9700838530 /* BloomFilter.h */, - 1A0C0F2B17780A9700838530 /* Char16.h */, - 1A0C0F2C17780A9700838530 /* CheckedInt.h */, - 1A0C0F2D17780A9700838530 /* Compiler.h */, - 1A0C0F2E17780A9700838530 /* Constants.h */, - 1A0C0F2F17780A9700838530 /* DebugOnly.h */, - 1A0C0F3017780A9700838530 /* EnumSet.h */, - 1A0C0F3117780A9700838530 /* FloatingPoint.h */, - 1A0C0F3217780A9700838530 /* GuardObjects.h */, - 1A0C0F3317780A9700838530 /* HashFunctions.h */, - 1A0C0F3417780A9700838530 /* Likely.h */, - 1A0C0F3517780A9700838530 /* LinkedList.h */, - 1A0C0F3617780A9700838530 /* MathAlgorithms.h */, - 1A0C0F3717780A9700838530 /* MemoryChecking.h */, - 1A0C0F3817780A9700838530 /* MSStdInt.h */, - 1A0C0F3917780A9700838530 /* NullPtr.h */, - 1A0C0F3A17780A9700838530 /* Range.h */, - 1A0C0F3B17780A9700838530 /* RangedPtr.h */, - 1A0C0F3C17780A9700838530 /* RefPtr.h */, - 1A0C0F3D17780A9700838530 /* Scoped.h */, - 1A0C0F3E17780A9700838530 /* SHA1.h */, - 1A0C0F3F17780A9700838530 /* SplayTree.h */, - 1A0C0F4017780A9700838530 /* StandardInteger.h */, - 1A0C0F4117780A9700838530 /* ThreadLocal.h */, - 1A0C0F4217780A9700838530 /* TypedEnum.h */, - 1A0C0F4317780A9700838530 /* Types.h */, - 1A0C0F4417780A9700838530 /* TypeTraits.h */, - 1A0C0F4517780A9700838530 /* Util.h */, - 1A0C0F4617780A9700838530 /* WeakPtr.h */, - ); - path = mozilla; - sourceTree = ""; - }; - 1A0C0F4717780A9700838530 /* lib */ = { - isa = PBXGroup; - children = ( - 1A0C0F4817780A9700838530 /* libjs_static.a */, - ); - path = lib; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 1A0C0E861778088700838530 /* jsbindings */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1A0C0E951778088700838530 /* Build configuration list for PBXNativeTarget "jsbindings" */; - buildPhases = ( - 1A0C0E831778088700838530 /* Sources */, - 1A0C0E841778088700838530 /* Frameworks */, - 1A0C0E851778088700838530 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = jsbindings; - productName = jsbindings; - productReference = 1A0C0E871778088700838530 /* libjsbindings.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 1A0C0E7F1778088700838530 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0460; - }; - buildConfigurationList = 1A0C0E821778088700838530 /* Build configuration list for PBXProject "jsbindings" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 1A0C0E7E1778088700838530; - productRefGroup = 1A0C0E881778088700838530 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 1A0C0E861778088700838530 /* jsbindings */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 1A0C0E831778088700838530 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E46D51778162E0055514D /* jsb_cocos2dx_extension_auto.cpp in Sources */, - 1A0C0EDA1778095000838530 /* cocos2d_specifics.cpp in Sources */, - 1A0C0EDB1778095000838530 /* cocosjs_manual_conversions.cpp in Sources */, - 1A0C0EDC1778095000838530 /* jsb_cocos2dx_auto.cpp in Sources */, - 1A0C0EEC1778095000838530 /* js_bindings_ccbreader.cpp in Sources */, - 1A0C0EED1778095000838530 /* js_bindings_chipmunk_auto_classes.cpp in Sources */, - 1A0C0EEE1778095000838530 /* js_bindings_chipmunk_functions.cpp in Sources */, - 1A0C0EEF1778095000838530 /* js_bindings_chipmunk_manual.cpp in Sources */, - 1A0C0EF01778095000838530 /* js_bindings_chipmunk_registration.cpp in Sources */, - 1A0C0EF11778095000838530 /* js_bindings_core.cpp in Sources */, - 1A0C0EF21778095000838530 /* js_bindings_opengl.cpp in Sources */, - 1A0C0EF31778095000838530 /* js_bindings_system_functions.cpp in Sources */, - 1A0C0EF41778095000838530 /* js_bindings_system_registration.cpp in Sources */, - 1A0C0EF51778095000838530 /* js_manual_conversions.cpp in Sources */, - 1A0C0EF61778095000838530 /* jsb_cocos2dx_extension_manual.cpp in Sources */, - 1A0C0EF71778095000838530 /* jsb_opengl_functions.cpp in Sources */, - 1A0C0EF81778095000838530 /* jsb_opengl_manual.cpp in Sources */, - 1A0C0EF91778095000838530 /* jsb_opengl_registration.cpp in Sources */, - 1A0C0EFA1778095000838530 /* jsb_websocket.cpp in Sources */, - 1A0C0EFB1778095000838530 /* ScriptingCore.cpp in Sources */, - 1A0C0EFC1778095000838530 /* XMLHTTPRequest.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1A0C0E931778088700838530 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 1A0C0E941778088700838530 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 1A0C0E961778088700838530 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - DSTROOT = /tmp/jsbindings.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "jsbindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - CC_TARGET_OS_IPHONE, - "COCOS2D_DEBUG=1", - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - "$(inherited)", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../../external/libwebsockets/ios/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../external\"", - "\"$(SRCROOT)/../../../../extensions\"", - "\"$(SRCROOT)/../../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../../extensions/network\"", - "\"$(SRCROOT)/../../../../cocos2dx\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios/Simulation\"", - "\"$(SRCROOT)/../../spidermonkey-ios/include\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../spidermonkey-ios/lib\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 1A0C0E971778088700838530 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - DSTROOT = /tmp/jsbindings.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "jsbindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - CC_TARGET_OS_IPHONE, - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../../external/libwebsockets/ios/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../external\"", - "\"$(SRCROOT)/../../../../extensions\"", - "\"$(SRCROOT)/../../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../../extensions/network\"", - "\"$(SRCROOT)/../../../../cocos2dx\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios/Simulation\"", - "\"$(SRCROOT)/../../spidermonkey-ios/include\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../spidermonkey-ios/lib\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1A0C0E821778088700838530 /* Build configuration list for PBXProject "jsbindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A0C0E931778088700838530 /* Debug */, - 1A0C0E941778088700838530 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1A0C0E951778088700838530 /* Build configuration list for PBXNativeTarget "jsbindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A0C0E961778088700838530 /* Debug */, - 1A0C0E971778088700838530 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 1A0C0E7F1778088700838530 /* Project object */; -} diff --git a/cocos/scripting/javascript/bindings/proj.mac/jsbindings-Prefix.pch b/cocos/scripting/javascript/bindings/proj.mac/jsbindings-Prefix.pch deleted file mode 100644 index af8c4a19d5..0000000000 --- a/cocos/scripting/javascript/bindings/proj.mac/jsbindings-Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'jsbindings' target in the 'jsbindings' project -// - -#ifdef __OBJC__ - #import -#endif diff --git a/cocos/scripting/javascript/bindings/proj.mac/jsbindings.xcodeproj/project.pbxproj b/cocos/scripting/javascript/bindings/proj.mac/jsbindings.xcodeproj/project.pbxproj deleted file mode 100644 index fd51d91ed6..0000000000 --- a/cocos/scripting/javascript/bindings/proj.mac/jsbindings.xcodeproj/project.pbxproj +++ /dev/null @@ -1,651 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1A0C0E8B1778088700838530 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C0E8A1778088700838530 /* Foundation.framework */; }; - 1A0C0EDA1778095000838530 /* cocos2d_specifics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */; }; - 1A0C0EDB1778095000838530 /* cocosjs_manual_conversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */; }; - 1A0C0EDC1778095000838530 /* jsb_cocos2dx_auto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */; }; - 1A0C0EEC1778095000838530 /* js_bindings_ccbreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */; }; - 1A0C0EED1778095000838530 /* js_bindings_chipmunk_auto_classes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */; }; - 1A0C0EEE1778095000838530 /* js_bindings_chipmunk_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */; }; - 1A0C0EEF1778095000838530 /* js_bindings_chipmunk_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */; }; - 1A0C0EF01778095000838530 /* js_bindings_chipmunk_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */; }; - 1A0C0EF11778095000838530 /* js_bindings_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */; }; - 1A0C0EF21778095000838530 /* js_bindings_opengl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */; }; - 1A0C0EF31778095000838530 /* js_bindings_system_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */; }; - 1A0C0EF41778095000838530 /* js_bindings_system_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */; }; - 1A0C0EF51778095000838530 /* js_manual_conversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */; }; - 1A0C0EF61778095000838530 /* jsb_cocos2dx_extension_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */; }; - 1A0C0EF71778095000838530 /* jsb_opengl_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */; }; - 1A0C0EF81778095000838530 /* jsb_opengl_manual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */; }; - 1A0C0EF91778095000838530 /* jsb_opengl_registration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */; }; - 1A0C0EFA1778095000838530 /* jsb_websocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED31778095000838530 /* jsb_websocket.cpp */; }; - 1A0C0EFB1778095000838530 /* ScriptingCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED51778095000838530 /* ScriptingCore.cpp */; }; - 1A0C0EFC1778095000838530 /* XMLHTTPRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */; }; - 1A6E46D51778162E0055514D /* jsb_cocos2dx_extension_auto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */; }; - A00B437317795C5C00480238 /* libjs_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A00B437217795C5C00480238 /* libjs_static.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 1A0C0E851778088700838530 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1A0C0E871778088700838530 /* libjsbindings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsbindings.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A0C0E8A1778088700838530 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cocos2d_specifics.cpp; path = ../cocos2d_specifics.cpp; sourceTree = ""; }; - 1A0C0E9A1778095000838530 /* cocos2d_specifics.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = cocos2d_specifics.hpp; path = ../cocos2d_specifics.hpp; sourceTree = ""; }; - 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cocosjs_manual_conversions.cpp; path = ../cocosjs_manual_conversions.cpp; sourceTree = ""; }; - 1A0C0E9C1778095000838530 /* cocosjs_manual_conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocosjs_manual_conversions.h; path = ../cocosjs_manual_conversions.h; sourceTree = ""; }; - 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsb_cocos2dx_auto.cpp; sourceTree = ""; }; - 1A0C0E9F1778095000838530 /* jsb_cocos2dx_auto.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsb_cocos2dx_auto.hpp; sourceTree = ""; }; - 1A0C0EA01778095000838530 /* jsb_cocos2dx_auto_api.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2dx_auto_api.js; sourceTree = ""; }; - 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsb_cocos2dx_extension_auto.cpp; sourceTree = ""; }; - 1A0C0EA21778095000838530 /* jsb_cocos2dx_extension_auto.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsb_cocos2dx_extension_auto.hpp; sourceTree = ""; }; - 1A0C0EA31778095000838530 /* jsb_cocos2dx_extension_auto_api.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2dx_extension_auto_api.js; sourceTree = ""; }; - 1A0C0EA41778095000838530 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 1A0C0EA61778095000838530 /* jsb.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb.js; sourceTree = ""; }; - 1A0C0EA71778095000838530 /* jsb_chipmunk.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_chipmunk.js; sourceTree = ""; }; - 1A0C0EA81778095000838530 /* jsb_chipmunk_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_chipmunk_constants.js; sourceTree = ""; }; - 1A0C0EA91778095000838530 /* jsb_cocos2d.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d.js; sourceTree = ""; }; - 1A0C0EAA1778095000838530 /* jsb_cocos2d_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d_constants.js; sourceTree = ""; }; - 1A0C0EAB1778095000838530 /* jsb_cocos2d_extension.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocos2d_extension.js; sourceTree = ""; }; - 1A0C0EAC1778095000838530 /* jsb_cocosbuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_cocosbuilder.js; sourceTree = ""; }; - 1A0C0EAD1778095000838530 /* jsb_debugger.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_debugger.js; sourceTree = ""; }; - 1A0C0EAE1778095000838530 /* jsb_opengl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_opengl.js; sourceTree = ""; }; - 1A0C0EAF1778095000838530 /* jsb_opengl_constants.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_opengl_constants.js; sourceTree = ""; }; - 1A0C0EB01778095000838530 /* jsb_sys.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsb_sys.js; sourceTree = ""; }; - 1A0C0EB11778095000838530 /* main.debug.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = main.debug.js; sourceTree = ""; }; - 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_ccbreader.cpp; path = ../js_bindings_ccbreader.cpp; sourceTree = ""; }; - 1A0C0EB31778095000838530 /* js_bindings_ccbreader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_ccbreader.h; path = ../js_bindings_ccbreader.h; sourceTree = ""; }; - 1A0C0EB41778095000838530 /* js_bindings_chipmunk_auto_classes_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_auto_classes_registration.h; path = ../js_bindings_chipmunk_auto_classes_registration.h; sourceTree = ""; }; - 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_auto_classes.cpp; path = ../js_bindings_chipmunk_auto_classes.cpp; sourceTree = ""; }; - 1A0C0EB61778095000838530 /* js_bindings_chipmunk_auto_classes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_auto_classes.h; path = ../js_bindings_chipmunk_auto_classes.h; sourceTree = ""; }; - 1A0C0EB71778095000838530 /* js_bindings_chipmunk_functions_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_functions_registration.h; path = ../js_bindings_chipmunk_functions_registration.h; sourceTree = ""; }; - 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_functions.cpp; path = ../js_bindings_chipmunk_functions.cpp; sourceTree = ""; }; - 1A0C0EB91778095000838530 /* js_bindings_chipmunk_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_functions.h; path = ../js_bindings_chipmunk_functions.h; sourceTree = ""; }; - 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_manual.cpp; path = ../js_bindings_chipmunk_manual.cpp; sourceTree = ""; }; - 1A0C0EBB1778095000838530 /* js_bindings_chipmunk_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_manual.h; path = ../js_bindings_chipmunk_manual.h; sourceTree = ""; }; - 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_chipmunk_registration.cpp; path = ../js_bindings_chipmunk_registration.cpp; sourceTree = ""; }; - 1A0C0EBD1778095000838530 /* js_bindings_chipmunk_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_chipmunk_registration.h; path = ../js_bindings_chipmunk_registration.h; sourceTree = ""; }; - 1A0C0EBE1778095000838530 /* js_bindings_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_config.h; path = ../js_bindings_config.h; sourceTree = ""; }; - 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_core.cpp; path = ../js_bindings_core.cpp; sourceTree = ""; }; - 1A0C0EC01778095000838530 /* js_bindings_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_core.h; path = ../js_bindings_core.h; sourceTree = ""; }; - 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_opengl.cpp; path = ../js_bindings_opengl.cpp; sourceTree = ""; }; - 1A0C0EC21778095000838530 /* js_bindings_opengl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_opengl.h; path = ../js_bindings_opengl.h; sourceTree = ""; }; - 1A0C0EC31778095000838530 /* js_bindings_system_functions_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_functions_registration.h; path = ../js_bindings_system_functions_registration.h; sourceTree = ""; }; - 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_system_functions.cpp; path = ../js_bindings_system_functions.cpp; sourceTree = ""; }; - 1A0C0EC51778095000838530 /* js_bindings_system_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_functions.h; path = ../js_bindings_system_functions.h; sourceTree = ""; }; - 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_bindings_system_registration.cpp; path = ../js_bindings_system_registration.cpp; sourceTree = ""; }; - 1A0C0EC71778095000838530 /* js_bindings_system_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_bindings_system_registration.h; path = ../js_bindings_system_registration.h; sourceTree = ""; }; - 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = js_manual_conversions.cpp; path = ../js_manual_conversions.cpp; sourceTree = ""; }; - 1A0C0EC91778095000838530 /* js_manual_conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js_manual_conversions.h; path = ../js_manual_conversions.h; sourceTree = ""; }; - 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_cocos2dx_extension_manual.cpp; path = ../jsb_cocos2dx_extension_manual.cpp; sourceTree = ""; }; - 1A0C0ECB1778095000838530 /* jsb_cocos2dx_extension_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_cocos2dx_extension_manual.h; path = ../jsb_cocos2dx_extension_manual.h; sourceTree = ""; }; - 1A0C0ECC1778095000838530 /* jsb_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_helper.h; path = ../jsb_helper.h; sourceTree = ""; }; - 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_functions.cpp; path = ../jsb_opengl_functions.cpp; sourceTree = ""; }; - 1A0C0ECE1778095000838530 /* jsb_opengl_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_functions.h; path = ../jsb_opengl_functions.h; sourceTree = ""; }; - 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_manual.cpp; path = ../jsb_opengl_manual.cpp; sourceTree = ""; }; - 1A0C0ED01778095000838530 /* jsb_opengl_manual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_manual.h; path = ../jsb_opengl_manual.h; sourceTree = ""; }; - 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_opengl_registration.cpp; path = ../jsb_opengl_registration.cpp; sourceTree = ""; }; - 1A0C0ED21778095000838530 /* jsb_opengl_registration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_opengl_registration.h; path = ../jsb_opengl_registration.h; sourceTree = ""; }; - 1A0C0ED31778095000838530 /* jsb_websocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsb_websocket.cpp; path = ../jsb_websocket.cpp; sourceTree = ""; }; - 1A0C0ED41778095000838530 /* jsb_websocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsb_websocket.h; path = ../jsb_websocket.h; sourceTree = ""; }; - 1A0C0ED51778095000838530 /* ScriptingCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptingCore.cpp; path = ../ScriptingCore.cpp; sourceTree = ""; }; - 1A0C0ED61778095000838530 /* ScriptingCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptingCore.h; path = ../ScriptingCore.h; sourceTree = ""; }; - 1A0C0ED71778095000838530 /* spidermonkey_specifics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spidermonkey_specifics.h; path = ../spidermonkey_specifics.h; sourceTree = ""; }; - 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XMLHTTPRequest.cpp; path = ../XMLHTTPRequest.cpp; sourceTree = ""; }; - 1A0C0ED91778095000838530 /* XMLHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMLHTTPRequest.h; path = ../XMLHTTPRequest.h; sourceTree = ""; }; - A00B437217795C5C00480238 /* libjs_static.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libjs_static.a; sourceTree = ""; }; - A05FCAF5177D12D900BE600E /* Anchor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Anchor.h; sourceTree = ""; }; - A05FCAF6177D12D900BE600E /* CallArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallArgs.h; sourceTree = ""; }; - A05FCAF7177D12D900BE600E /* CharacterEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterEncoding.h; sourceTree = ""; }; - A05FCAF8177D12D900BE600E /* GCAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCAPI.h; sourceTree = ""; }; - A05FCAF9177D12D900BE600E /* HashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashTable.h; sourceTree = ""; }; - A05FCAFA177D12D900BE600E /* HeapAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapAPI.h; sourceTree = ""; }; - A05FCAFB177D12D900BE600E /* LegacyIntTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyIntTypes.h; sourceTree = ""; }; - A05FCAFC177D12D900BE600E /* MemoryMetrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryMetrics.h; sourceTree = ""; }; - A05FCAFD177D12D900BE600E /* PropertyKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyKey.h; sourceTree = ""; }; - A05FCAFE177D12D900BE600E /* RequiredDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequiredDefines.h; sourceTree = ""; }; - A05FCAFF177D12D900BE600E /* RootingAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootingAPI.h; sourceTree = ""; }; - A05FCB00177D12D900BE600E /* TemplateLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateLib.h; sourceTree = ""; }; - A05FCB01177D12D900BE600E /* Utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utility.h; sourceTree = ""; }; - A05FCB02177D12D900BE600E /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Value.h; sourceTree = ""; }; - A05FCB03177D12D900BE600E /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = ""; }; - A05FCB04177D12D900BE600E /* js-config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "js-config.h"; sourceTree = ""; }; - A05FCB05177D12D900BE600E /* js.msg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = js.msg; sourceTree = ""; }; - A05FCB06177D12D900BE600E /* jsalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsalloc.h; sourceTree = ""; }; - A05FCB07177D12D900BE600E /* jsapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsapi.h; sourceTree = ""; }; - A05FCB08177D12D900BE600E /* jsclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsclass.h; sourceTree = ""; }; - A05FCB09177D12D900BE600E /* jsclist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsclist.h; sourceTree = ""; }; - A05FCB0A177D12D900BE600E /* jscpucfg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jscpucfg.h; sourceTree = ""; }; - A05FCB0B177D12D900BE600E /* jsdbgapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsdbgapi.h; sourceTree = ""; }; - A05FCB0C177D12D900BE600E /* jsdhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsdhash.h; sourceTree = ""; }; - A05FCB0D177D12D900BE600E /* jsfriendapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsfriendapi.h; sourceTree = ""; }; - A05FCB0E177D12D900BE600E /* jslock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jslock.h; sourceTree = ""; }; - A05FCB0F177D12D900BE600E /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = ""; }; - A05FCB10177D12D900BE600E /* jsperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsperf.h; sourceTree = ""; }; - A05FCB11177D12D900BE600E /* jsprf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprf.h; sourceTree = ""; }; - A05FCB12177D12D900BE600E /* jsprototypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprototypes.h; sourceTree = ""; }; - A05FCB13177D12D900BE600E /* jsproxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsproxy.h; sourceTree = ""; }; - A05FCB14177D12D900BE600E /* jsprvtd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsprvtd.h; sourceTree = ""; }; - A05FCB15177D12D900BE600E /* jspubtd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jspubtd.h; sourceTree = ""; }; - A05FCB16177D12D900BE600E /* jstypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jstypes.h; sourceTree = ""; }; - A05FCB17177D12D900BE600E /* jsutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsutil.h; sourceTree = ""; }; - A05FCB18177D12D900BE600E /* jsversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsversion.h; sourceTree = ""; }; - A05FCB19177D12D900BE600E /* jswrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jswrapper.h; sourceTree = ""; }; - A05FCB1B177D12D900BE600E /* Assertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Assertions.h; sourceTree = ""; }; - A05FCB1C177D12D900BE600E /* Attributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attributes.h; sourceTree = ""; }; - A05FCB1D177D12D900BE600E /* BloomFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BloomFilter.h; sourceTree = ""; }; - A05FCB1E177D12D900BE600E /* Char16.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Char16.h; sourceTree = ""; }; - A05FCB1F177D12D900BE600E /* CheckedInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckedInt.h; sourceTree = ""; }; - A05FCB20177D12D900BE600E /* Compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Compiler.h; sourceTree = ""; }; - A05FCB21177D12D900BE600E /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; - A05FCB22177D12D900BE600E /* DebugOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugOnly.h; sourceTree = ""; }; - A05FCB23177D12D900BE600E /* EnumSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumSet.h; sourceTree = ""; }; - A05FCB24177D12D900BE600E /* FloatingPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatingPoint.h; sourceTree = ""; }; - A05FCB25177D12D900BE600E /* GuardObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GuardObjects.h; sourceTree = ""; }; - A05FCB26177D12D900BE600E /* HashFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashFunctions.h; sourceTree = ""; }; - A05FCB27177D12D900BE600E /* Likely.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Likely.h; sourceTree = ""; }; - A05FCB28177D12D900BE600E /* LinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkedList.h; sourceTree = ""; }; - A05FCB29177D12D900BE600E /* MathAlgorithms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathAlgorithms.h; sourceTree = ""; }; - A05FCB2A177D12D900BE600E /* MemoryChecking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryChecking.h; sourceTree = ""; }; - A05FCB2B177D12D900BE600E /* MSStdInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSStdInt.h; sourceTree = ""; }; - A05FCB2C177D12D900BE600E /* NullPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullPtr.h; sourceTree = ""; }; - A05FCB2D177D12D900BE600E /* Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Range.h; sourceTree = ""; }; - A05FCB2E177D12D900BE600E /* RangedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangedPtr.h; sourceTree = ""; }; - A05FCB2F177D12D900BE600E /* RefPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefPtr.h; sourceTree = ""; }; - A05FCB30177D12D900BE600E /* Scoped.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scoped.h; sourceTree = ""; }; - A05FCB31177D12D900BE600E /* SHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHA1.h; sourceTree = ""; }; - A05FCB32177D12D900BE600E /* SplayTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SplayTree.h; sourceTree = ""; }; - A05FCB33177D12D900BE600E /* StandardInteger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StandardInteger.h; sourceTree = ""; }; - A05FCB34177D12D900BE600E /* ThreadLocal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadLocal.h; sourceTree = ""; }; - A05FCB35177D12D900BE600E /* TypedEnum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedEnum.h; sourceTree = ""; }; - A05FCB36177D12D900BE600E /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = ""; }; - A05FCB37177D12D900BE600E /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = ""; }; - A05FCB38177D12D900BE600E /* Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Util.h; sourceTree = ""; }; - A05FCB39177D12D900BE600E /* WeakPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakPtr.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1A0C0E841778088700838530 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A0C0E8B1778088700838530 /* Foundation.framework in Frameworks */, - A00B437317795C5C00480238 /* libjs_static.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1A0C0E7E1778088700838530 = { - isa = PBXGroup; - children = ( - 1A0C0E981778093E00838530 /* bindings */, - 1A0C0E891778088700838530 /* Frameworks */, - 1A0C0E881778088700838530 /* Products */, - ); - sourceTree = ""; - }; - 1A0C0E881778088700838530 /* Products */ = { - isa = PBXGroup; - children = ( - 1A0C0E871778088700838530 /* libjsbindings.a */, - ); - name = Products; - sourceTree = ""; - }; - 1A0C0E891778088700838530 /* Frameworks */ = { - isa = PBXGroup; - children = ( - A00B432717795C5C00480238 /* spidermonkey-mac */, - 1A0C0E8A1778088700838530 /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 1A0C0E981778093E00838530 /* bindings */ = { - isa = PBXGroup; - children = ( - 1A0C0E991778095000838530 /* cocos2d_specifics.cpp */, - 1A0C0E9A1778095000838530 /* cocos2d_specifics.hpp */, - 1A0C0E9B1778095000838530 /* cocosjs_manual_conversions.cpp */, - 1A0C0E9C1778095000838530 /* cocosjs_manual_conversions.h */, - 1A0C0E9D1778095000838530 /* generated */, - 1A0C0EA51778095000838530 /* js */, - 1A0C0EB21778095000838530 /* js_bindings_ccbreader.cpp */, - 1A0C0EB31778095000838530 /* js_bindings_ccbreader.h */, - 1A0C0EB41778095000838530 /* js_bindings_chipmunk_auto_classes_registration.h */, - 1A0C0EB51778095000838530 /* js_bindings_chipmunk_auto_classes.cpp */, - 1A0C0EB61778095000838530 /* js_bindings_chipmunk_auto_classes.h */, - 1A0C0EB71778095000838530 /* js_bindings_chipmunk_functions_registration.h */, - 1A0C0EB81778095000838530 /* js_bindings_chipmunk_functions.cpp */, - 1A0C0EB91778095000838530 /* js_bindings_chipmunk_functions.h */, - 1A0C0EBA1778095000838530 /* js_bindings_chipmunk_manual.cpp */, - 1A0C0EBB1778095000838530 /* js_bindings_chipmunk_manual.h */, - 1A0C0EBC1778095000838530 /* js_bindings_chipmunk_registration.cpp */, - 1A0C0EBD1778095000838530 /* js_bindings_chipmunk_registration.h */, - 1A0C0EBE1778095000838530 /* js_bindings_config.h */, - 1A0C0EBF1778095000838530 /* js_bindings_core.cpp */, - 1A0C0EC01778095000838530 /* js_bindings_core.h */, - 1A0C0EC11778095000838530 /* js_bindings_opengl.cpp */, - 1A0C0EC21778095000838530 /* js_bindings_opengl.h */, - 1A0C0EC31778095000838530 /* js_bindings_system_functions_registration.h */, - 1A0C0EC41778095000838530 /* js_bindings_system_functions.cpp */, - 1A0C0EC51778095000838530 /* js_bindings_system_functions.h */, - 1A0C0EC61778095000838530 /* js_bindings_system_registration.cpp */, - 1A0C0EC71778095000838530 /* js_bindings_system_registration.h */, - 1A0C0EC81778095000838530 /* js_manual_conversions.cpp */, - 1A0C0EC91778095000838530 /* js_manual_conversions.h */, - 1A0C0ECA1778095000838530 /* jsb_cocos2dx_extension_manual.cpp */, - 1A0C0ECB1778095000838530 /* jsb_cocos2dx_extension_manual.h */, - 1A0C0ECC1778095000838530 /* jsb_helper.h */, - 1A0C0ECD1778095000838530 /* jsb_opengl_functions.cpp */, - 1A0C0ECE1778095000838530 /* jsb_opengl_functions.h */, - 1A0C0ECF1778095000838530 /* jsb_opengl_manual.cpp */, - 1A0C0ED01778095000838530 /* jsb_opengl_manual.h */, - 1A0C0ED11778095000838530 /* jsb_opengl_registration.cpp */, - 1A0C0ED21778095000838530 /* jsb_opengl_registration.h */, - 1A0C0ED31778095000838530 /* jsb_websocket.cpp */, - 1A0C0ED41778095000838530 /* jsb_websocket.h */, - 1A0C0ED51778095000838530 /* ScriptingCore.cpp */, - 1A0C0ED61778095000838530 /* ScriptingCore.h */, - 1A0C0ED71778095000838530 /* spidermonkey_specifics.h */, - 1A0C0ED81778095000838530 /* XMLHTTPRequest.cpp */, - 1A0C0ED91778095000838530 /* XMLHTTPRequest.h */, - ); - name = bindings; - sourceTree = ""; - }; - 1A0C0E9D1778095000838530 /* generated */ = { - isa = PBXGroup; - children = ( - 1A0C0E9E1778095000838530 /* jsb_cocos2dx_auto.cpp */, - 1A0C0E9F1778095000838530 /* jsb_cocos2dx_auto.hpp */, - 1A0C0EA01778095000838530 /* jsb_cocos2dx_auto_api.js */, - 1A0C0EA11778095000838530 /* jsb_cocos2dx_extension_auto.cpp */, - 1A0C0EA21778095000838530 /* jsb_cocos2dx_extension_auto.hpp */, - 1A0C0EA31778095000838530 /* jsb_cocos2dx_extension_auto_api.js */, - 1A0C0EA41778095000838530 /* README */, - ); - name = generated; - path = ../generated; - sourceTree = ""; - }; - 1A0C0EA51778095000838530 /* js */ = { - isa = PBXGroup; - children = ( - 1A0C0EA61778095000838530 /* jsb.js */, - 1A0C0EA71778095000838530 /* jsb_chipmunk.js */, - 1A0C0EA81778095000838530 /* jsb_chipmunk_constants.js */, - 1A0C0EA91778095000838530 /* jsb_cocos2d.js */, - 1A0C0EAA1778095000838530 /* jsb_cocos2d_constants.js */, - 1A0C0EAB1778095000838530 /* jsb_cocos2d_extension.js */, - 1A0C0EAC1778095000838530 /* jsb_cocosbuilder.js */, - 1A0C0EAD1778095000838530 /* jsb_debugger.js */, - 1A0C0EAE1778095000838530 /* jsb_opengl.js */, - 1A0C0EAF1778095000838530 /* jsb_opengl_constants.js */, - 1A0C0EB01778095000838530 /* jsb_sys.js */, - 1A0C0EB11778095000838530 /* main.debug.js */, - ); - name = js; - path = ../js; - sourceTree = ""; - }; - A00B432717795C5C00480238 /* spidermonkey-mac */ = { - isa = PBXGroup; - children = ( - A00B432817795C5C00480238 /* include */, - A00B437117795C5C00480238 /* lib */, - ); - name = "spidermonkey-mac"; - path = "../../spidermonkey-mac"; - sourceTree = ""; - }; - A00B432817795C5C00480238 /* include */ = { - isa = PBXGroup; - children = ( - A05FCAF4177D12D900BE600E /* js */, - A05FCB04177D12D900BE600E /* js-config.h */, - A05FCB05177D12D900BE600E /* js.msg */, - A05FCB06177D12D900BE600E /* jsalloc.h */, - A05FCB07177D12D900BE600E /* jsapi.h */, - A05FCB08177D12D900BE600E /* jsclass.h */, - A05FCB09177D12D900BE600E /* jsclist.h */, - A05FCB0A177D12D900BE600E /* jscpucfg.h */, - A05FCB0B177D12D900BE600E /* jsdbgapi.h */, - A05FCB0C177D12D900BE600E /* jsdhash.h */, - A05FCB0D177D12D900BE600E /* jsfriendapi.h */, - A05FCB0E177D12D900BE600E /* jslock.h */, - A05FCB0F177D12D900BE600E /* json.h */, - A05FCB10177D12D900BE600E /* jsperf.h */, - A05FCB11177D12D900BE600E /* jsprf.h */, - A05FCB12177D12D900BE600E /* jsprototypes.h */, - A05FCB13177D12D900BE600E /* jsproxy.h */, - A05FCB14177D12D900BE600E /* jsprvtd.h */, - A05FCB15177D12D900BE600E /* jspubtd.h */, - A05FCB16177D12D900BE600E /* jstypes.h */, - A05FCB17177D12D900BE600E /* jsutil.h */, - A05FCB18177D12D900BE600E /* jsversion.h */, - A05FCB19177D12D900BE600E /* jswrapper.h */, - A05FCB1A177D12D900BE600E /* mozilla */, - ); - path = include; - sourceTree = ""; - }; - A00B437117795C5C00480238 /* lib */ = { - isa = PBXGroup; - children = ( - A00B437217795C5C00480238 /* libjs_static.a */, - ); - path = lib; - sourceTree = ""; - }; - A05FCAF4177D12D900BE600E /* js */ = { - isa = PBXGroup; - children = ( - A05FCAF5177D12D900BE600E /* Anchor.h */, - A05FCAF6177D12D900BE600E /* CallArgs.h */, - A05FCAF7177D12D900BE600E /* CharacterEncoding.h */, - A05FCAF8177D12D900BE600E /* GCAPI.h */, - A05FCAF9177D12D900BE600E /* HashTable.h */, - A05FCAFA177D12D900BE600E /* HeapAPI.h */, - A05FCAFB177D12D900BE600E /* LegacyIntTypes.h */, - A05FCAFC177D12D900BE600E /* MemoryMetrics.h */, - A05FCAFD177D12D900BE600E /* PropertyKey.h */, - A05FCAFE177D12D900BE600E /* RequiredDefines.h */, - A05FCAFF177D12D900BE600E /* RootingAPI.h */, - A05FCB00177D12D900BE600E /* TemplateLib.h */, - A05FCB01177D12D900BE600E /* Utility.h */, - A05FCB02177D12D900BE600E /* Value.h */, - A05FCB03177D12D900BE600E /* Vector.h */, - ); - path = js; - sourceTree = ""; - }; - A05FCB1A177D12D900BE600E /* mozilla */ = { - isa = PBXGroup; - children = ( - A05FCB1B177D12D900BE600E /* Assertions.h */, - A05FCB1C177D12D900BE600E /* Attributes.h */, - A05FCB1D177D12D900BE600E /* BloomFilter.h */, - A05FCB1E177D12D900BE600E /* Char16.h */, - A05FCB1F177D12D900BE600E /* CheckedInt.h */, - A05FCB20177D12D900BE600E /* Compiler.h */, - A05FCB21177D12D900BE600E /* Constants.h */, - A05FCB22177D12D900BE600E /* DebugOnly.h */, - A05FCB23177D12D900BE600E /* EnumSet.h */, - A05FCB24177D12D900BE600E /* FloatingPoint.h */, - A05FCB25177D12D900BE600E /* GuardObjects.h */, - A05FCB26177D12D900BE600E /* HashFunctions.h */, - A05FCB27177D12D900BE600E /* Likely.h */, - A05FCB28177D12D900BE600E /* LinkedList.h */, - A05FCB29177D12D900BE600E /* MathAlgorithms.h */, - A05FCB2A177D12D900BE600E /* MemoryChecking.h */, - A05FCB2B177D12D900BE600E /* MSStdInt.h */, - A05FCB2C177D12D900BE600E /* NullPtr.h */, - A05FCB2D177D12D900BE600E /* Range.h */, - A05FCB2E177D12D900BE600E /* RangedPtr.h */, - A05FCB2F177D12D900BE600E /* RefPtr.h */, - A05FCB30177D12D900BE600E /* Scoped.h */, - A05FCB31177D12D900BE600E /* SHA1.h */, - A05FCB32177D12D900BE600E /* SplayTree.h */, - A05FCB33177D12D900BE600E /* StandardInteger.h */, - A05FCB34177D12D900BE600E /* ThreadLocal.h */, - A05FCB35177D12D900BE600E /* TypedEnum.h */, - A05FCB36177D12D900BE600E /* Types.h */, - A05FCB37177D12D900BE600E /* TypeTraits.h */, - A05FCB38177D12D900BE600E /* Util.h */, - A05FCB39177D12D900BE600E /* WeakPtr.h */, - ); - path = mozilla; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 1A0C0E861778088700838530 /* jsbindings */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1A0C0E951778088700838530 /* Build configuration list for PBXNativeTarget "jsbindings" */; - buildPhases = ( - 1A0C0E831778088700838530 /* Sources */, - 1A0C0E841778088700838530 /* Frameworks */, - 1A0C0E851778088700838530 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = jsbindings; - productName = jsbindings; - productReference = 1A0C0E871778088700838530 /* libjsbindings.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 1A0C0E7F1778088700838530 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0460; - }; - buildConfigurationList = 1A0C0E821778088700838530 /* Build configuration list for PBXProject "jsbindings" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 1A0C0E7E1778088700838530; - productRefGroup = 1A0C0E881778088700838530 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 1A0C0E861778088700838530 /* jsbindings */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 1A0C0E831778088700838530 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E46D51778162E0055514D /* jsb_cocos2dx_extension_auto.cpp in Sources */, - 1A0C0EDA1778095000838530 /* cocos2d_specifics.cpp in Sources */, - 1A0C0EDB1778095000838530 /* cocosjs_manual_conversions.cpp in Sources */, - 1A0C0EDC1778095000838530 /* jsb_cocos2dx_auto.cpp in Sources */, - 1A0C0EEC1778095000838530 /* js_bindings_ccbreader.cpp in Sources */, - 1A0C0EED1778095000838530 /* js_bindings_chipmunk_auto_classes.cpp in Sources */, - 1A0C0EEE1778095000838530 /* js_bindings_chipmunk_functions.cpp in Sources */, - 1A0C0EEF1778095000838530 /* js_bindings_chipmunk_manual.cpp in Sources */, - 1A0C0EF01778095000838530 /* js_bindings_chipmunk_registration.cpp in Sources */, - 1A0C0EF11778095000838530 /* js_bindings_core.cpp in Sources */, - 1A0C0EF21778095000838530 /* js_bindings_opengl.cpp in Sources */, - 1A0C0EF31778095000838530 /* js_bindings_system_functions.cpp in Sources */, - 1A0C0EF41778095000838530 /* js_bindings_system_registration.cpp in Sources */, - 1A0C0EF51778095000838530 /* js_manual_conversions.cpp in Sources */, - 1A0C0EF61778095000838530 /* jsb_cocos2dx_extension_manual.cpp in Sources */, - 1A0C0EF71778095000838530 /* jsb_opengl_functions.cpp in Sources */, - 1A0C0EF81778095000838530 /* jsb_opengl_manual.cpp in Sources */, - 1A0C0EF91778095000838530 /* jsb_opengl_registration.cpp in Sources */, - 1A0C0EFA1778095000838530 /* jsb_websocket.cpp in Sources */, - 1A0C0EFB1778095000838530 /* ScriptingCore.cpp in Sources */, - 1A0C0EFC1778095000838530 /* XMLHTTPRequest.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1A0C0E931778088700838530 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - CC_TARGET_OS_MAC, - CC_KEYBOARD_SUPPORT, - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - 1A0C0E941778088700838530 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = ( - NDEBUG, - CC_TARGET_OS_MAC, - CC_KEYBOARD_SUPPORT, - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - SDKROOT = macosx; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 1A0C0E961778088700838530 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/jsbindings.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "jsbindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "COCOS2D_DEBUG=1", - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../../external/libwebsockets/mac/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../external\"", - "\"$(SRCROOT)/../../../../extensions\"", - "\"$(SRCROOT)/../../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../../extensions/network\"", - "\"$(SRCROOT)/../../../../cocos2dx\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/mac\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/mac\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/mac/Simulation\"", - "\"$(SRCROOT)/../../spidermonkey-mac/include\"", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../spidermonkey-mac/lib\"", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 1A0C0E971778088700838530 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/jsbindings.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "jsbindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../../external/libwebsockets/mac/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../external\"", - "\"$(SRCROOT)/../../../../extensions\"", - "\"$(SRCROOT)/../../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../../extensions/network\"", - "\"$(SRCROOT)/../../../../cocos2dx\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/mac\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/mac\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/mac/Simulation\"", - "\"$(SRCROOT)/../../spidermonkey-mac/include\"", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../spidermonkey-mac/lib\"", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1A0C0E821778088700838530 /* Build configuration list for PBXProject "jsbindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A0C0E931778088700838530 /* Debug */, - 1A0C0E941778088700838530 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1A0C0E951778088700838530 /* Build configuration list for PBXNativeTarget "jsbindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A0C0E961778088700838530 /* Debug */, - 1A0C0E971778088700838530 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 1A0C0E7F1778088700838530 /* Project object */; -} diff --git a/cocos/scripting/lua/proj.ios/luabindings.xcodeproj/project.pbxproj b/cocos/scripting/lua/proj.ios/luabindings.xcodeproj/project.pbxproj deleted file mode 100644 index 0bc70a8e36..0000000000 --- a/cocos/scripting/lua/proj.ios/luabindings.xcodeproj/project.pbxproj +++ /dev/null @@ -1,453 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1A6E476E17781A660055514D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E476D17781A660055514D /* Foundation.framework */; }; - 1A6E487E17781AB00055514D /* CCBProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E477C17781AB00055514D /* CCBProxy.cpp */; }; - 1A6E487F17781AB00055514D /* CCLuaBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E477E17781AB00055514D /* CCLuaBridge.cpp */; }; - 1A6E488017781AB00055514D /* CCLuaEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478017781AB00055514D /* CCLuaEngine.cpp */; }; - 1A6E488117781AB00055514D /* CCLuaStack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478217781AB00055514D /* CCLuaStack.cpp */; }; - 1A6E488217781AB00055514D /* CCLuaValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478417781AB00055514D /* CCLuaValue.cpp */; }; - 1A6E488317781AB00055514D /* Cocos2dxLuaLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478617781AB00055514D /* Cocos2dxLuaLoader.cpp */; }; - 1A6E488417781AB00055514D /* Lua_extensions_CCB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478817781AB00055514D /* Lua_extensions_CCB.cpp */; }; - 1A6E488517781AB00055514D /* Lua_web_socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478A17781AB00055514D /* Lua_web_socket.cpp */; }; - 1A6E488617781AB00055514D /* LuaCocos2d.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478C17781AB00055514D /* LuaCocos2d.cpp */; }; - 1A6E488717781AB00055514D /* LuaOpengl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E478E17781AB00055514D /* LuaOpengl.cpp */; }; - 1A6E488817781AB00055514D /* LuaScrollView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E479017781AB00055514D /* LuaScrollView.cpp */; }; - 1A6E488917781AB00055514D /* CCLuaObjcBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E479517781AB00055514D /* CCLuaObjcBridge.mm */; }; - 1A6E488A17781AB00055514D /* tolua_fix.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E479617781AB00055514D /* tolua_fix.c */; }; - 1A6E488E17781AB00055514D /* libluajit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E47AA17781AB00055514D /* libluajit.a */; }; - 1A6E48D717781AB00055514D /* tolua_event.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E487817781AB00055514D /* tolua_event.c */; }; - 1A6E48D817781AB00055514D /* tolua_is.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E487A17781AB00055514D /* tolua_is.c */; }; - 1A6E48D917781AB00055514D /* tolua_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E487B17781AB00055514D /* tolua_map.c */; }; - 1A6E48DA17781AB00055514D /* tolua_push.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E487C17781AB00055514D /* tolua_push.c */; }; - 1A6E48DB17781AB00055514D /* tolua_to.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A6E487D17781AB00055514D /* tolua_to.c */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 1A6E476817781A660055514D /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/${PRODUCT_NAME}"; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1A6E476A17781A660055514D /* libluabindings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libluabindings.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E476D17781A660055514D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1A6E477C17781AB00055514D /* CCBProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCBProxy.cpp; sourceTree = ""; }; - 1A6E477D17781AB00055514D /* CCBProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCBProxy.h; sourceTree = ""; }; - 1A6E477E17781AB00055514D /* CCLuaBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCLuaBridge.cpp; sourceTree = ""; }; - 1A6E477F17781AB00055514D /* CCLuaBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLuaBridge.h; sourceTree = ""; }; - 1A6E478017781AB00055514D /* CCLuaEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCLuaEngine.cpp; sourceTree = ""; }; - 1A6E478117781AB00055514D /* CCLuaEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLuaEngine.h; sourceTree = ""; }; - 1A6E478217781AB00055514D /* CCLuaStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCLuaStack.cpp; sourceTree = ""; }; - 1A6E478317781AB00055514D /* CCLuaStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLuaStack.h; sourceTree = ""; }; - 1A6E478417781AB00055514D /* CCLuaValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCLuaValue.cpp; sourceTree = ""; }; - 1A6E478517781AB00055514D /* CCLuaValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLuaValue.h; sourceTree = ""; }; - 1A6E478617781AB00055514D /* Cocos2dxLuaLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cocos2dxLuaLoader.cpp; sourceTree = ""; }; - 1A6E478717781AB00055514D /* Cocos2dxLuaLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cocos2dxLuaLoader.h; sourceTree = ""; }; - 1A6E478817781AB00055514D /* Lua_extensions_CCB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lua_extensions_CCB.cpp; sourceTree = ""; }; - 1A6E478917781AB00055514D /* Lua_extensions_CCB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lua_extensions_CCB.h; sourceTree = ""; }; - 1A6E478A17781AB00055514D /* Lua_web_socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lua_web_socket.cpp; sourceTree = ""; }; - 1A6E478B17781AB00055514D /* Lua_web_socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lua_web_socket.h; sourceTree = ""; }; - 1A6E478C17781AB00055514D /* LuaCocos2d.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LuaCocos2d.cpp; sourceTree = ""; }; - 1A6E478D17781AB00055514D /* LuaCocos2d.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LuaCocos2d.h; sourceTree = ""; }; - 1A6E478E17781AB00055514D /* LuaOpengl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LuaOpengl.cpp; sourceTree = ""; }; - 1A6E478F17781AB00055514D /* LuaOpengl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LuaOpengl.h; sourceTree = ""; }; - 1A6E479017781AB00055514D /* LuaScrollView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LuaScrollView.cpp; sourceTree = ""; }; - 1A6E479117781AB00055514D /* LuaScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LuaScrollView.h; sourceTree = ""; }; - 1A6E479417781AB00055514D /* CCLuaObjcBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLuaObjcBridge.h; sourceTree = ""; }; - 1A6E479517781AB00055514D /* CCLuaObjcBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CCLuaObjcBridge.mm; sourceTree = ""; }; - 1A6E479617781AB00055514D /* tolua_fix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_fix.c; sourceTree = ""; }; - 1A6E479717781AB00055514D /* tolua_fix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tolua_fix.h; sourceTree = ""; }; - 1A6E47A517781AB00055514D /* lauxlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lauxlib.h; sourceTree = ""; }; - 1A6E47A617781AB00055514D /* lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua.h; sourceTree = ""; }; - 1A6E47A717781AB00055514D /* luaconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = luaconf.h; sourceTree = ""; }; - 1A6E47A817781AB00055514D /* lualib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lualib.h; sourceTree = ""; }; - 1A6E47AA17781AB00055514D /* libluajit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libluajit.a; sourceTree = ""; }; - 1A6E487717781AB00055514D /* tolua++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "tolua++.h"; sourceTree = ""; }; - 1A6E487817781AB00055514D /* tolua_event.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_event.c; sourceTree = ""; }; - 1A6E487917781AB00055514D /* tolua_event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tolua_event.h; sourceTree = ""; }; - 1A6E487A17781AB00055514D /* tolua_is.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_is.c; sourceTree = ""; }; - 1A6E487B17781AB00055514D /* tolua_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_map.c; sourceTree = ""; }; - 1A6E487C17781AB00055514D /* tolua_push.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_push.c; sourceTree = ""; }; - 1A6E487D17781AB00055514D /* tolua_to.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tolua_to.c; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1A6E476717781A660055514D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E476E17781A660055514D /* Foundation.framework in Frameworks */, - 1A6E488E17781AB00055514D /* libluajit.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1A6E476117781A660055514D = { - isa = PBXGroup; - children = ( - 1A6E477B17781AB00055514D /* cocos2dx_support */, - 1A6E479817781AB00055514D /* luajit */, - 1A6E487617781AB00055514D /* tolua */, - 1A6E476C17781A660055514D /* Frameworks */, - 1A6E476B17781A660055514D /* Products */, - ); - sourceTree = ""; - }; - 1A6E476B17781A660055514D /* Products */ = { - isa = PBXGroup; - children = ( - 1A6E476A17781A660055514D /* libluabindings.a */, - ); - name = Products; - sourceTree = ""; - }; - 1A6E476C17781A660055514D /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1A6E476D17781A660055514D /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 1A6E477B17781AB00055514D /* cocos2dx_support */ = { - isa = PBXGroup; - children = ( - 1A6E477C17781AB00055514D /* CCBProxy.cpp */, - 1A6E477D17781AB00055514D /* CCBProxy.h */, - 1A6E477E17781AB00055514D /* CCLuaBridge.cpp */, - 1A6E477F17781AB00055514D /* CCLuaBridge.h */, - 1A6E478017781AB00055514D /* CCLuaEngine.cpp */, - 1A6E478117781AB00055514D /* CCLuaEngine.h */, - 1A6E478217781AB00055514D /* CCLuaStack.cpp */, - 1A6E478317781AB00055514D /* CCLuaStack.h */, - 1A6E478417781AB00055514D /* CCLuaValue.cpp */, - 1A6E478517781AB00055514D /* CCLuaValue.h */, - 1A6E478617781AB00055514D /* Cocos2dxLuaLoader.cpp */, - 1A6E478717781AB00055514D /* Cocos2dxLuaLoader.h */, - 1A6E478817781AB00055514D /* Lua_extensions_CCB.cpp */, - 1A6E478917781AB00055514D /* Lua_extensions_CCB.h */, - 1A6E478A17781AB00055514D /* Lua_web_socket.cpp */, - 1A6E478B17781AB00055514D /* Lua_web_socket.h */, - 1A6E478C17781AB00055514D /* LuaCocos2d.cpp */, - 1A6E478D17781AB00055514D /* LuaCocos2d.h */, - 1A6E478E17781AB00055514D /* LuaOpengl.cpp */, - 1A6E478F17781AB00055514D /* LuaOpengl.h */, - 1A6E479017781AB00055514D /* LuaScrollView.cpp */, - 1A6E479117781AB00055514D /* LuaScrollView.h */, - 1A6E479217781AB00055514D /* platform */, - 1A6E479617781AB00055514D /* tolua_fix.c */, - 1A6E479717781AB00055514D /* tolua_fix.h */, - ); - name = cocos2dx_support; - path = ../cocos2dx_support; - sourceTree = ""; - }; - 1A6E479217781AB00055514D /* platform */ = { - isa = PBXGroup; - children = ( - 1A6E479317781AB00055514D /* ios */, - ); - path = platform; - sourceTree = ""; - }; - 1A6E479317781AB00055514D /* ios */ = { - isa = PBXGroup; - children = ( - 1A6E479417781AB00055514D /* CCLuaObjcBridge.h */, - 1A6E479517781AB00055514D /* CCLuaObjcBridge.mm */, - ); - path = ios; - sourceTree = ""; - }; - 1A6E479817781AB00055514D /* luajit */ = { - isa = PBXGroup; - children = ( - 1A6E47A417781AB00055514D /* include */, - 1A6E47A917781AB00055514D /* ios */, - ); - name = luajit; - path = ../luajit; - sourceTree = ""; - }; - 1A6E47A417781AB00055514D /* include */ = { - isa = PBXGroup; - children = ( - 1A6E47A517781AB00055514D /* lauxlib.h */, - 1A6E47A617781AB00055514D /* lua.h */, - 1A6E47A717781AB00055514D /* luaconf.h */, - 1A6E47A817781AB00055514D /* lualib.h */, - ); - path = include; - sourceTree = ""; - }; - 1A6E47A917781AB00055514D /* ios */ = { - isa = PBXGroup; - children = ( - 1A6E47AA17781AB00055514D /* libluajit.a */, - ); - path = ios; - sourceTree = ""; - }; - 1A6E487617781AB00055514D /* tolua */ = { - isa = PBXGroup; - children = ( - 1A6E487717781AB00055514D /* tolua++.h */, - 1A6E487817781AB00055514D /* tolua_event.c */, - 1A6E487917781AB00055514D /* tolua_event.h */, - 1A6E487A17781AB00055514D /* tolua_is.c */, - 1A6E487B17781AB00055514D /* tolua_map.c */, - 1A6E487C17781AB00055514D /* tolua_push.c */, - 1A6E487D17781AB00055514D /* tolua_to.c */, - ); - name = tolua; - path = ../tolua; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 1A6E476917781A660055514D /* luabindings */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1A6E477817781A660055514D /* Build configuration list for PBXNativeTarget "luabindings" */; - buildPhases = ( - 1A6E476617781A660055514D /* Sources */, - 1A6E476717781A660055514D /* Frameworks */, - 1A6E476817781A660055514D /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = luabindings; - productName = luabindings; - productReference = 1A6E476A17781A660055514D /* libluabindings.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 1A6E476217781A660055514D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0460; - }; - buildConfigurationList = 1A6E476517781A660055514D /* Build configuration list for PBXProject "luabindings" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 1A6E476117781A660055514D; - productRefGroup = 1A6E476B17781A660055514D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 1A6E476917781A660055514D /* luabindings */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 1A6E476617781A660055514D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E487E17781AB00055514D /* CCBProxy.cpp in Sources */, - 1A6E487F17781AB00055514D /* CCLuaBridge.cpp in Sources */, - 1A6E488017781AB00055514D /* CCLuaEngine.cpp in Sources */, - 1A6E488117781AB00055514D /* CCLuaStack.cpp in Sources */, - 1A6E488217781AB00055514D /* CCLuaValue.cpp in Sources */, - 1A6E488317781AB00055514D /* Cocos2dxLuaLoader.cpp in Sources */, - 1A6E488417781AB00055514D /* Lua_extensions_CCB.cpp in Sources */, - 1A6E488517781AB00055514D /* Lua_web_socket.cpp in Sources */, - 1A6E488617781AB00055514D /* LuaCocos2d.cpp in Sources */, - 1A6E488717781AB00055514D /* LuaOpengl.cpp in Sources */, - 1A6E488817781AB00055514D /* LuaScrollView.cpp in Sources */, - 1A6E488917781AB00055514D /* CCLuaObjcBridge.mm in Sources */, - 1A6E488A17781AB00055514D /* tolua_fix.c in Sources */, - 1A6E48D717781AB00055514D /* tolua_event.c in Sources */, - 1A6E48D817781AB00055514D /* tolua_is.c in Sources */, - 1A6E48D917781AB00055514D /* tolua_map.c in Sources */, - 1A6E48DA17781AB00055514D /* tolua_push.c in Sources */, - 1A6E48DB17781AB00055514D /* tolua_to.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1A6E477617781A660055514D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 1A6E477717781A660055514D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 1A6E477917781A660055514D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - DSTROOT = /tmp/luabindings.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "luabindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - CC_TARGET_OS_IPHONE, - "COCOS2D_DEBUG=1", - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - "$(inherited)", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../external/libwebsockets/ios/include\"", - "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../external\"", - "\"$(SRCROOT)/../../../extensions\"", - "\"$(SRCROOT)/../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../extensions/network\"", - "\"$(SRCROOT)/../../../cocos2dx\"", - "\"$(SRCROOT)/../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/ios/Simulation\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../luajit/ios\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 1A6E477A17781A660055514D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - DSTROOT = /tmp/luabindings.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "luabindings-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - CC_TARGET_OS_IPHONE, - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../../CocosDenshion/include", - "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", - "\"$(SRCROOT)/../../../external/libwebsockets/ios/include\"", - "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../external\"", - "\"$(SRCROOT)/../../../extensions\"", - "\"$(SRCROOT)/../../../extensions/LocalStorage\"", - "\"$(SRCROOT)/../../../extensions/network\"", - "\"$(SRCROOT)/../../../cocos2dx\"", - "\"$(SRCROOT)/../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../cocos2dx/platform/ios/Simulation\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../luajit/ios\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1A6E476517781A660055514D /* Build configuration list for PBXProject "luabindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A6E477617781A660055514D /* Debug */, - 1A6E477717781A660055514D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1A6E477817781A660055514D /* Build configuration list for PBXNativeTarget "luabindings" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A6E477917781A660055514D /* Debug */, - 1A6E477A17781A660055514D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 1A6E476217781A660055514D /* Project object */; -} diff --git a/samples/Lua/HelloLua/proj.ios/HelloLua.xcodeproj/project.pbxproj b/samples/Lua/HelloLua/proj.ios/HelloLua.xcodeproj/project.pbxproj deleted file mode 100644 index 1531215d78..0000000000 --- a/samples/Lua/HelloLua/proj.ios/HelloLua.xcodeproj/project.pbxproj +++ /dev/null @@ -1,491 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1A6E48DF17781C0F0055514D /* libcocos2dx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48DC17781C0F0055514D /* libcocos2dx.a */; }; - 1A6E48E017781C0F0055514D /* libCocosDenshion.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48DD17781C0F0055514D /* libCocosDenshion.a */; }; - 1A6E48E117781C0F0055514D /* libluabindings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48DE17781C0F0055514D /* libluabindings.a */; }; - 1A6E48F017781D600055514D /* libchipmunk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48EE17781D600055514D /* libchipmunk.a */; }; - 1A6E48F317781D920055514D /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48F217781D920055514D /* libBox2D.a */; }; - 1A6E4902177821FB0055514D /* libextensions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E4901177821FB0055514D /* libextensions.a */; }; - 1A6E49081778251B0055514D /* AudioEngine.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E49041778251B0055514D /* AudioEngine.lua */; }; - 1A6E49091778251B0055514D /* CCBReaderLoad.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E49051778251B0055514D /* CCBReaderLoad.lua */; }; - 1A6E490A1778251B0055514D /* Cocos2dConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E49061778251B0055514D /* Cocos2dConstants.lua */; }; - 1A6E490B1778251B0055514D /* OpenglConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E49071778251B0055514D /* OpenglConstants.lua */; }; - 506EDBA5102F4C9F00A389B3 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 506EDBA4102F4C9F00A389B3 /* AVFoundation.framework */; }; - 78947C6D14EBB9B100DBD5A6 /* background.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 78947C5E14EBB9B000DBD5A6 /* background.mp3 */; }; - 78947C6E14EBB9B100DBD5A6 /* crop.png in Resources */ = {isa = PBXBuildFile; fileRef = 78947C5F14EBB9B000DBD5A6 /* crop.png */; }; - 78947C7014EBB9B100DBD5A6 /* dog.png in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6114EBB9B000DBD5A6 /* dog.png */; }; - 78947C7114EBB9B100DBD5A6 /* effect1.wav in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6214EBB9B000DBD5A6 /* effect1.wav */; }; - 78947C7214EBB9B100DBD5A6 /* farm.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6314EBB9B000DBD5A6 /* farm.jpg */; }; - 78947C7414EBB9B100DBD5A6 /* hello.lua in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6614EBB9B000DBD5A6 /* hello.lua */; }; - 78947C7514EBB9B100DBD5A6 /* hello2.lua in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6714EBB9B000DBD5A6 /* hello2.lua */; }; - 78947C7714EBB9B100DBD5A6 /* land.png in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6914EBB9B000DBD5A6 /* land.png */; }; - 78947C7814EBB9B100DBD5A6 /* menu1.png in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6A14EBB9B000DBD5A6 /* menu1.png */; }; - 78947C7914EBB9B100DBD5A6 /* menu2.png in Resources */ = {isa = PBXBuildFile; fileRef = 78947C6B14EBB9B000DBD5A6 /* menu2.png */; }; - 78DC4C9A15490B9500317402 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 78DC4C9815490B9500317402 /* Default.png */; }; - BF82F41713A864D700616D55 /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF82F41513A864D700616D55 /* AppDelegate.cpp */; }; - BF82F42113A8652A00616D55 /* AppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF82F41F13A8652A00616D55 /* AppController.mm */; }; - BF82F42213A8652A00616D55 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BF82F42013A8652A00616D55 /* main.m */; }; - D41A0AA2160F13F8004552AE /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D41A0AA1160F13F8004552AE /* Default-568h@2x.png */; }; - D446FD3B16102085000ADA7B /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D446FD3A16102085000ADA7B /* Default@2x.png */; }; - D4CEAD7913B4634300780515 /* RootViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = D4CEAD7713B4634300780515 /* RootViewController.mm */; }; - D4EF94D715BD311700D803EB /* Icon-57.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF94D615BD311700D803EB /* Icon-57.png */; }; - D4EF94D915BD311A00D803EB /* Icon-114.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF94D815BD311A00D803EB /* Icon-114.png */; }; - D4EF94DB15BD311E00D803EB /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF94DA15BD311E00D803EB /* Icon-72.png */; }; - D4EF94DD15BD312100D803EB /* Icon-144.png in Resources */ = {isa = PBXBuildFile; fileRef = D4EF94DC15BD312100D803EB /* Icon-144.png */; }; - DC6640030F83B3EA000B3E49 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC6640020F83B3EA000B3E49 /* AudioToolbox.framework */; }; - DC6640050F83B3EA000B3E49 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC6640040F83B3EA000B3E49 /* OpenAL.framework */; }; - DCCBF1B70F6022AE0040855A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCBF1B60F6022AE0040855A /* CoreGraphics.framework */; }; - DCCBF1B90F6022AE0040855A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCBF1B80F6022AE0040855A /* Foundation.framework */; }; - DCCBF1BB0F6022AE0040855A /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCBF1BA0F6022AE0040855A /* OpenGLES.framework */; }; - DCCBF1BD0F6022AE0040855A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCBF1BC0F6022AE0040855A /* QuartzCore.framework */; }; - DCCBF1BF0F6022AE0040855A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCBF1BE0F6022AE0040855A /* UIKit.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 1A6E48DC17781C0F0055514D /* libcocos2dx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libcocos2dx.a; path = "libcocos2dx.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48DD17781C0F0055514D /* libCocosDenshion.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libCocosDenshion.a; path = "libCocosDenshion.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48DE17781C0F0055514D /* libluabindings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libluabindings.a; path = "libluabindings.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48EE17781D600055514D /* libchipmunk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libchipmunk.a; path = "libchipmunk.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48F217781D920055514D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libBox2D.a; path = "libBox2D.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E4901177821FB0055514D /* libextensions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libextensions.a; path = "libextensions.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E49041778251B0055514D /* AudioEngine.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AudioEngine.lua; sourceTree = ""; }; - 1A6E49051778251B0055514D /* CCBReaderLoad.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CCBReaderLoad.lua; sourceTree = ""; }; - 1A6E49061778251B0055514D /* Cocos2dConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cocos2dConstants.lua; sourceTree = ""; }; - 1A6E49071778251B0055514D /* OpenglConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OpenglConstants.lua; sourceTree = ""; }; - 1D6058910D05DD3D006BFB54 /* HelloLua.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloLua.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 506EDBA4102F4C9F00A389B3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - 78947C5E14EBB9B000DBD5A6 /* background.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = background.mp3; sourceTree = ""; }; - 78947C5F14EBB9B000DBD5A6 /* crop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = crop.png; sourceTree = ""; }; - 78947C6114EBB9B000DBD5A6 /* dog.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dog.png; sourceTree = ""; }; - 78947C6214EBB9B000DBD5A6 /* effect1.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = effect1.wav; sourceTree = ""; }; - 78947C6314EBB9B000DBD5A6 /* farm.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = farm.jpg; sourceTree = ""; }; - 78947C6614EBB9B000DBD5A6 /* hello.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hello.lua; sourceTree = ""; }; - 78947C6714EBB9B000DBD5A6 /* hello2.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hello2.lua; sourceTree = ""; }; - 78947C6914EBB9B000DBD5A6 /* land.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = land.png; sourceTree = ""; }; - 78947C6A14EBB9B000DBD5A6 /* menu1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu1.png; sourceTree = ""; }; - 78947C6B14EBB9B000DBD5A6 /* menu2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu2.png; sourceTree = ""; }; - 78DC4C9815490B9500317402 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = SOURCE_ROOT; }; - BF82F41513A864D700616D55 /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AppDelegate.cpp; path = ../Classes/AppDelegate.cpp; sourceTree = SOURCE_ROOT; }; - BF82F41613A864D700616D55 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ../Classes/AppDelegate.h; sourceTree = SOURCE_ROOT; }; - BF82F41E13A8652A00616D55 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; - BF82F41F13A8652A00616D55 /* AppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppController.mm; sourceTree = ""; }; - BF82F42013A8652A00616D55 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - BF82F42313A8654600616D55 /* HelloLua_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelloLua_Prefix.pch; sourceTree = ""; }; - D41A0AA1160F13F8004552AE /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../proj.ios/Default-568h@2x.png"; sourceTree = ""; }; - D446FD3A16102085000ADA7B /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default@2x.png"; path = "../proj.ios/Default@2x.png"; sourceTree = ""; }; - D4CEAD7713B4634300780515 /* RootViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RootViewController.mm; sourceTree = ""; }; - D4CEAD7813B4634300780515 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; - D4EF94D615BD311700D803EB /* Icon-57.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-57.png"; path = "../proj.ios/Icon-57.png"; sourceTree = ""; }; - D4EF94D815BD311A00D803EB /* Icon-114.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-114.png"; path = "../proj.ios/Icon-114.png"; sourceTree = ""; }; - D4EF94DA15BD311E00D803EB /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-72.png"; path = "../proj.ios/Icon-72.png"; sourceTree = ""; }; - D4EF94DC15BD312100D803EB /* Icon-144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-144.png"; path = "../proj.ios/Icon-144.png"; sourceTree = ""; }; - DC6640020F83B3EA000B3E49 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; - DC6640040F83B3EA000B3E49 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; - DCCBF1B60F6022AE0040855A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - DCCBF1B80F6022AE0040855A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - DCCBF1BA0F6022AE0040855A /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; - DCCBF1BC0F6022AE0040855A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - DCCBF1BE0F6022AE0040855A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E4902177821FB0055514D /* libextensions.a in Frameworks */, - 1A6E48F317781D920055514D /* libBox2D.a in Frameworks */, - 1A6E48F017781D600055514D /* libchipmunk.a in Frameworks */, - 1A6E48DF17781C0F0055514D /* libcocos2dx.a in Frameworks */, - 1A6E48E017781C0F0055514D /* libCocosDenshion.a in Frameworks */, - 1A6E48E117781C0F0055514D /* libluabindings.a in Frameworks */, - DCCBF1B70F6022AE0040855A /* CoreGraphics.framework in Frameworks */, - DCCBF1B90F6022AE0040855A /* Foundation.framework in Frameworks */, - DCCBF1BB0F6022AE0040855A /* OpenGLES.framework in Frameworks */, - DCCBF1BD0F6022AE0040855A /* QuartzCore.framework in Frameworks */, - DCCBF1BF0F6022AE0040855A /* UIKit.framework in Frameworks */, - DC6640030F83B3EA000B3E49 /* AudioToolbox.framework in Frameworks */, - DC6640050F83B3EA000B3E49 /* OpenAL.framework in Frameworks */, - 506EDBA5102F4C9F00A389B3 /* AVFoundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 19C28FACFE9D520D11CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 1D6058910D05DD3D006BFB54 /* HelloLua.app */, - ); - name = Products; - sourceTree = ""; - }; - 1A6E49031778251B0055514D /* script */ = { - isa = PBXGroup; - children = ( - 1A6E49041778251B0055514D /* AudioEngine.lua */, - 1A6E49051778251B0055514D /* CCBReaderLoad.lua */, - 1A6E49061778251B0055514D /* Cocos2dConstants.lua */, - 1A6E49071778251B0055514D /* OpenglConstants.lua */, - ); - name = script; - path = ../../../../scripting/lua/script; - sourceTree = ""; - }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { - isa = PBXGroup; - children = ( - BF82F41413A864B000616D55 /* Classes */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, - 29B97315FDCFA39411CA2CEA /* Other Sources */, - 19C28FACFE9D520D11CA2CBB /* Products */, - 78947C5C14EBB9B000DBD5A6 /* Resources */, - ); - name = CustomTemplate; - sourceTree = ""; - }; - 29B97315FDCFA39411CA2CEA /* Other Sources */ = { - isa = PBXGroup; - children = ( - D4CEAD7713B4634300780515 /* RootViewController.mm */, - D4CEAD7813B4634300780515 /* RootViewController.h */, - BF82F42313A8654600616D55 /* HelloLua_Prefix.pch */, - BF82F41E13A8652A00616D55 /* AppController.h */, - BF82F41F13A8652A00616D55 /* AppController.mm */, - BF82F42013A8652A00616D55 /* main.m */, - ); - name = "Other Sources"; - sourceTree = ""; - }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1A6E48F217781D920055514D /* libBox2D.a */, - 1A6E48EE17781D600055514D /* libchipmunk.a */, - 1A6E48DC17781C0F0055514D /* libcocos2dx.a */, - 1A6E48DD17781C0F0055514D /* libCocosDenshion.a */, - 1A6E4901177821FB0055514D /* libextensions.a */, - 1A6E48DE17781C0F0055514D /* libluabindings.a */, - DCCBF1B60F6022AE0040855A /* CoreGraphics.framework */, - DCCBF1B80F6022AE0040855A /* Foundation.framework */, - DCCBF1BA0F6022AE0040855A /* OpenGLES.framework */, - DCCBF1BC0F6022AE0040855A /* QuartzCore.framework */, - DCCBF1BE0F6022AE0040855A /* UIKit.framework */, - DC6640040F83B3EA000B3E49 /* OpenAL.framework */, - DC6640020F83B3EA000B3E49 /* AudioToolbox.framework */, - 506EDBA4102F4C9F00A389B3 /* AVFoundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 78947C5C14EBB9B000DBD5A6 /* Resources */ = { - isa = PBXGroup; - children = ( - 1A6E49031778251B0055514D /* script */, - D4EF94DC15BD312100D803EB /* Icon-144.png */, - D4EF94DA15BD311E00D803EB /* Icon-72.png */, - D4EF94D815BD311A00D803EB /* Icon-114.png */, - D4EF94D615BD311700D803EB /* Icon-57.png */, - 78947C5E14EBB9B000DBD5A6 /* background.mp3 */, - 78947C5F14EBB9B000DBD5A6 /* crop.png */, - 78947C6114EBB9B000DBD5A6 /* dog.png */, - 78947C6214EBB9B000DBD5A6 /* effect1.wav */, - 78947C6314EBB9B000DBD5A6 /* farm.jpg */, - 78947C6614EBB9B000DBD5A6 /* hello.lua */, - 78947C6714EBB9B000DBD5A6 /* hello2.lua */, - 78947C6914EBB9B000DBD5A6 /* land.png */, - 78947C6A14EBB9B000DBD5A6 /* menu1.png */, - 78947C6B14EBB9B000DBD5A6 /* menu2.png */, - 78DC4C9815490B9500317402 /* Default.png */, - D446FD3A16102085000ADA7B /* Default@2x.png */, - D41A0AA1160F13F8004552AE /* Default-568h@2x.png */, - ); - name = Resources; - path = ../Resources; - sourceTree = ""; - }; - BF82F41413A864B000616D55 /* Classes */ = { - isa = PBXGroup; - children = ( - BF82F41513A864D700616D55 /* AppDelegate.cpp */, - BF82F41613A864D700616D55 /* AppDelegate.h */, - ); - name = Classes; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 1D6058900D05DD3D006BFB54 /* HelloLua */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloLua" */; - buildPhases = ( - 1D60588D0D05DD3D006BFB54 /* Resources */, - 1D60588E0D05DD3D006BFB54 /* Sources */, - 1D60588F0D05DD3D006BFB54 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = HelloLua; - productName = HelloLua; - productReference = 1D6058910D05DD3D006BFB54 /* HelloLua.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 29B97313FDCFA39411CA2CEA /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0430; - }; - buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloLua" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 1D6058900D05DD3D006BFB54 /* HelloLua */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 1D60588D0D05DD3D006BFB54 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 78947C6D14EBB9B100DBD5A6 /* background.mp3 in Resources */, - 78947C6E14EBB9B100DBD5A6 /* crop.png in Resources */, - 78947C7014EBB9B100DBD5A6 /* dog.png in Resources */, - 78947C7114EBB9B100DBD5A6 /* effect1.wav in Resources */, - 78947C7214EBB9B100DBD5A6 /* farm.jpg in Resources */, - 78947C7414EBB9B100DBD5A6 /* hello.lua in Resources */, - 78947C7514EBB9B100DBD5A6 /* hello2.lua in Resources */, - 78947C7714EBB9B100DBD5A6 /* land.png in Resources */, - 78947C7814EBB9B100DBD5A6 /* menu1.png in Resources */, - 78947C7914EBB9B100DBD5A6 /* menu2.png in Resources */, - 78DC4C9A15490B9500317402 /* Default.png in Resources */, - D4EF94D715BD311700D803EB /* Icon-57.png in Resources */, - D4EF94D915BD311A00D803EB /* Icon-114.png in Resources */, - D4EF94DB15BD311E00D803EB /* Icon-72.png in Resources */, - D4EF94DD15BD312100D803EB /* Icon-144.png in Resources */, - D41A0AA2160F13F8004552AE /* Default-568h@2x.png in Resources */, - D446FD3B16102085000ADA7B /* Default@2x.png in Resources */, - 1A6E49081778251B0055514D /* AudioEngine.lua in Resources */, - 1A6E49091778251B0055514D /* CCBReaderLoad.lua in Resources */, - 1A6E490A1778251B0055514D /* Cocos2dConstants.lua in Resources */, - 1A6E490B1778251B0055514D /* OpenglConstants.lua in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 1D60588E0D05DD3D006BFB54 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF82F41713A864D700616D55 /* AppDelegate.cpp in Sources */, - BF82F42113A8652A00616D55 /* AppController.mm in Sources */, - BF82F42213A8652A00616D55 /* main.m in Sources */, - D4CEAD7913B4634300780515 /* RootViewController.mm in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1D6058940D05DD3E006BFB54 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_DYNAMIC_NO_PIC = NO; - GCC_FAST_OBJC_DISPATCH = YES; - GCC_INLINES_ARE_PRIVATE_EXTERN = NO; - GCC_OBJC_CALL_CXX_CDTORS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = HelloLua_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - USE_FILE32API, - CC_TARGET_OS_IPHONE, - "COCOS2D_DEBUG=1", - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; - GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../CocosDenshion/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/cocos2dx_support\"", - "\"$(SRCROOT)/../../../../scripting/lua/luajit/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/tolua\"", - ); - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios/libraries\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lz"; - PRODUCT_NAME = HelloLua; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = NO; - VALID_ARCHS = "armv7 armv7s"; - WARNING_CFLAGS = ""; - }; - name = Debug; - }; - 1D6058950D05DD3E006BFB54 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_FAST_OBJC_DISPATCH = YES; - GCC_INLINES_ARE_PRIVATE_EXTERN = NO; - GCC_OBJC_CALL_CXX_CDTORS = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = HelloLua_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - USE_FILE32API, - CC_TARGET_OS_IPHONE, - "CC_ENABLE_CHIPMUNK_INTEGRATION=1", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; - GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../CocosDenshion/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/cocos2dx_support\"", - "\"$(SRCROOT)/../../../../scripting/lua/luajit/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/tolua\"", - ); - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios/libraries\"", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lz"; - PRODUCT_NAME = HelloLua; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = NO; - VALID_ARCHS = "armv7 armv7s"; - WARNING_CFLAGS = ""; - }; - name = Release; - }; - C01FCF4F08A954540054247B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = ( - DEBUG, - "COCOS2D_DEBUG=1", - "CD_DEBUG=1", - ); - "GCC_THUMB_SUPPORT[arch=armv6]" = NO; - "GCC_THUMB_SUPPORT[arch=armv7]" = YES; - GCC_VERSION = ""; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "armv6 armv7 i386"; - }; - name = Debug; - }; - C01FCF5008A954540054247B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - "GCC_THUMB_SUPPORT[arch=armv6]" = NO; - "GCC_THUMB_SUPPORT[arch=armv7]" = YES; - GCC_UNROLL_LOOPS = YES; - GCC_VERSION = ""; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "armv6 armv7 i386"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HelloLua" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1D6058940D05DD3E006BFB54 /* Debug */, - 1D6058950D05DD3E006BFB54 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HelloLua" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C01FCF4F08A954540054247B /* Debug */, - C01FCF5008A954540054247B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; -} diff --git a/samples/Lua/TestLua/proj.ios/TestLua.xcodeproj/project.pbxproj b/samples/Lua/TestLua/proj.ios/TestLua.xcodeproj/project.pbxproj deleted file mode 100644 index 7d60946d93..0000000000 --- a/samples/Lua/TestLua/proj.ios/TestLua.xcodeproj/project.pbxproj +++ /dev/null @@ -1,573 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 159B8A28175D9A930005B47D /* cocosbuilderRes in Resources */ = {isa = PBXBuildFile; fileRef = 159B8A27175D9A930005B47D /* cocosbuilderRes */; }; - 15C156981683138E00D239F2 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156911683138E00D239F2 /* Default-568h@2x.png */; }; - 15C156991683138E00D239F2 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156921683138E00D239F2 /* Default.png */; }; - 15C1569A1683138E00D239F2 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156931683138E00D239F2 /* Default@2x.png */; }; - 15C1569B1683138E00D239F2 /* Icon-57.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156941683138E00D239F2 /* Icon-57.png */; }; - 15C1569C1683138E00D239F2 /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156951683138E00D239F2 /* Icon-72.png */; }; - 15C1569D1683138E00D239F2 /* Icon-114.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156961683138E00D239F2 /* Icon-114.png */; }; - 15C1569E1683138E00D239F2 /* Icon-144.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156971683138E00D239F2 /* Icon-144.png */; }; - 1A6E48E817781C2B0055514D /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48E217781C2B0055514D /* libBox2D.a */; }; - 1A6E48E917781C2B0055514D /* libchipmunk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48E317781C2B0055514D /* libchipmunk.a */; }; - 1A6E48EA17781C2B0055514D /* libcocos2dx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48E417781C2B0055514D /* libcocos2dx.a */; }; - 1A6E48EB17781C2B0055514D /* libCocosDenshion.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48E517781C2B0055514D /* libCocosDenshion.a */; }; - 1A6E48ED17781C2B0055514D /* libluabindings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48E717781C2B0055514D /* libluabindings.a */; }; - 1A6E48FB17781F9F0055514D /* AudioEngine.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E48F717781F9F0055514D /* AudioEngine.lua */; }; - 1A6E48FC17781F9F0055514D /* CCBReaderLoad.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E48F817781F9F0055514D /* CCBReaderLoad.lua */; }; - 1A6E48FD17781F9F0055514D /* Cocos2dConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E48F917781F9F0055514D /* Cocos2dConstants.lua */; }; - 1A6E48FE17781F9F0055514D /* OpenglConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A6E48FA17781F9F0055514D /* OpenglConstants.lua */; }; - 1A6E4900177821AF0055514D /* libextensions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6E48FF177821AF0055514D /* libextensions.a */; }; - 1AD263A2168350490089000C /* luaScript in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A1168350490089000C /* luaScript */; }; - 1AD263BB1683506D0089000C /* animations in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A31683506C0089000C /* animations */; }; - 1AD263BC1683506D0089000C /* app.icf in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A41683506C0089000C /* app.icf */; }; - 1AD263BD1683506D0089000C /* background.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A51683506C0089000C /* background.mp3 */; }; - 1AD263BE1683506D0089000C /* background.ogg in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A61683506C0089000C /* background.ogg */; }; - 1AD263BF1683506D0089000C /* ccb in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A71683506C0089000C /* ccb */; }; - 1AD263C01683506D0089000C /* CocosBuilderExample.ccbproj in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A81683506C0089000C /* CocosBuilderExample.ccbproj */; }; - 1AD263C11683506D0089000C /* CocosBuilderExample.ccbresourcelog in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263A91683506C0089000C /* CocosBuilderExample.ccbresourcelog */; }; - 1AD263C21683506D0089000C /* development.icf in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AA1683506C0089000C /* development.icf */; }; - 1AD263C31683506D0089000C /* effect1.raw in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AB1683506C0089000C /* effect1.raw */; }; - 1AD263C41683506D0089000C /* effect1.wav in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AC1683506C0089000C /* effect1.wav */; }; - 1AD263C51683506D0089000C /* effect2.ogg in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AD1683506C0089000C /* effect2.ogg */; }; - 1AD263C61683506D0089000C /* extensions in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AE1683506C0089000C /* extensions */; }; - 1AD263C71683506D0089000C /* fonts in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263AF1683506C0089000C /* fonts */; }; - 1AD263C81683506D0089000C /* fps_images.png in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B01683506C0089000C /* fps_images.png */; }; - 1AD263C91683506D0089000C /* hd in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B11683506C0089000C /* hd */; }; - 1AD263CA1683506D0089000C /* Hello.png in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B21683506C0089000C /* Hello.png */; }; - 1AD263CB1683506D0089000C /* Images in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B31683506C0089000C /* Images */; }; - 1AD263CC1683506D0089000C /* ipad in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B41683506C0089000C /* ipad */; }; - 1AD263CD1683506D0089000C /* ipadhd in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B51683506C0089000C /* ipadhd */; }; - 1AD263CE1683506D0089000C /* music.mid in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B61683506C0089000C /* music.mid */; }; - 1AD263CF1683506D0089000C /* Particles in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B71683506C0089000C /* Particles */; }; - 1AD263D01683506D0089000C /* Shaders in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B81683506C0089000C /* Shaders */; }; - 1AD263D11683506D0089000C /* TileMaps in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263B91683506C0089000C /* TileMaps */; }; - 1AD263D21683506D0089000C /* zwoptex in Resources */ = {isa = PBXBuildFile; fileRef = 1AD263BA1683506C0089000C /* zwoptex */; }; - F293B3CD15EB7BE500256477 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3CC15EB7BE500256477 /* QuartzCore.framework */; }; - F293B3CF15EB7BE500256477 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3CE15EB7BE500256477 /* OpenGLES.framework */; }; - F293B3D115EB7BE500256477 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D015EB7BE500256477 /* OpenAL.framework */; }; - F293B3D315EB7BE500256477 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D215EB7BE500256477 /* AudioToolbox.framework */; }; - F293B3D515EB7BE500256477 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D415EB7BE500256477 /* AVFoundation.framework */; }; - F293B3D715EB7BE500256477 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D615EB7BE500256477 /* UIKit.framework */; }; - F293B3D915EB7BE500256477 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D815EB7BE500256477 /* Foundation.framework */; }; - F293B3DB15EB7BE500256477 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3DA15EB7BE500256477 /* CoreGraphics.framework */; }; - F293B6FC15EB823D00256477 /* AppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F293B6F715EB823D00256477 /* AppController.mm */; }; - F293B6FD15EB823D00256477 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F293B6F815EB823D00256477 /* main.m */; }; - F293B6FE15EB823D00256477 /* RootViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F293B6FA15EB823D00256477 /* RootViewController.mm */; }; - F293BB9C15EB831F00256477 /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F293BB7E15EB831F00256477 /* AppDelegate.cpp */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 159B8A27175D9A930005B47D /* cocosbuilderRes */ = {isa = PBXFileReference; lastKnownFileType = folder; name = cocosbuilderRes; path = ../../../Lua/TestLua/Resources/cocosbuilderRes; sourceTree = ""; }; - 15C156911683138E00D239F2 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = SOURCE_ROOT; }; - 15C156921683138E00D239F2 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = SOURCE_ROOT; }; - 15C156931683138E00D239F2 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = SOURCE_ROOT; }; - 15C156941683138E00D239F2 /* Icon-57.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-57.png"; sourceTree = SOURCE_ROOT; }; - 15C156951683138E00D239F2 /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-72.png"; sourceTree = SOURCE_ROOT; }; - 15C156961683138E00D239F2 /* Icon-114.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-114.png"; sourceTree = SOURCE_ROOT; }; - 15C156971683138E00D239F2 /* Icon-144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-144.png"; sourceTree = SOURCE_ROOT; }; - 1A6E48E217781C2B0055514D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libBox2D.a; path = "libBox2D.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48E317781C2B0055514D /* libchipmunk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libchipmunk.a; path = "libchipmunk.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48E417781C2B0055514D /* libcocos2dx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libcocos2dx.a; path = "libcocos2dx.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48E517781C2B0055514D /* libCocosDenshion.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libCocosDenshion.a; path = "libCocosDenshion.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48E717781C2B0055514D /* libluabindings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libluabindings.a; path = "libluabindings.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A6E48F717781F9F0055514D /* AudioEngine.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AudioEngine.lua; sourceTree = ""; }; - 1A6E48F817781F9F0055514D /* CCBReaderLoad.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CCBReaderLoad.lua; sourceTree = ""; }; - 1A6E48F917781F9F0055514D /* Cocos2dConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cocos2dConstants.lua; sourceTree = ""; }; - 1A6E48FA17781F9F0055514D /* OpenglConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OpenglConstants.lua; sourceTree = ""; }; - 1A6E48FF177821AF0055514D /* libextensions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libextensions.a; path = "libextensions.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1AD263A1168350490089000C /* luaScript */ = {isa = PBXFileReference; lastKnownFileType = folder; name = luaScript; path = ../../../Lua/TestLua/Resources/luaScript; sourceTree = ""; }; - 1AD263A31683506C0089000C /* animations */ = {isa = PBXFileReference; lastKnownFileType = folder; path = animations; sourceTree = ""; }; - 1AD263A41683506C0089000C /* app.icf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = app.icf; sourceTree = ""; }; - 1AD263A51683506C0089000C /* background.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = background.mp3; sourceTree = ""; }; - 1AD263A61683506C0089000C /* background.ogg */ = {isa = PBXFileReference; lastKnownFileType = file; path = background.ogg; sourceTree = ""; }; - 1AD263A71683506C0089000C /* ccb */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ccb; sourceTree = ""; }; - 1AD263A81683506C0089000C /* CocosBuilderExample.ccbproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = CocosBuilderExample.ccbproj; sourceTree = ""; }; - 1AD263A91683506C0089000C /* CocosBuilderExample.ccbresourcelog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CocosBuilderExample.ccbresourcelog; sourceTree = ""; }; - 1AD263AA1683506C0089000C /* development.icf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = development.icf; sourceTree = ""; }; - 1AD263AB1683506C0089000C /* effect1.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = effect1.raw; sourceTree = ""; }; - 1AD263AC1683506C0089000C /* effect1.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = effect1.wav; sourceTree = ""; }; - 1AD263AD1683506C0089000C /* effect2.ogg */ = {isa = PBXFileReference; lastKnownFileType = file; path = effect2.ogg; sourceTree = ""; }; - 1AD263AE1683506C0089000C /* extensions */ = {isa = PBXFileReference; lastKnownFileType = folder; path = extensions; sourceTree = ""; }; - 1AD263AF1683506C0089000C /* fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = fonts; sourceTree = ""; }; - 1AD263B01683506C0089000C /* fps_images.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fps_images.png; sourceTree = ""; }; - 1AD263B11683506C0089000C /* hd */ = {isa = PBXFileReference; lastKnownFileType = folder; path = hd; sourceTree = ""; }; - 1AD263B21683506C0089000C /* Hello.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Hello.png; sourceTree = ""; }; - 1AD263B31683506C0089000C /* Images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Images; sourceTree = ""; }; - 1AD263B41683506C0089000C /* ipad */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ipad; sourceTree = ""; }; - 1AD263B51683506C0089000C /* ipadhd */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ipadhd; sourceTree = ""; }; - 1AD263B61683506C0089000C /* music.mid */ = {isa = PBXFileReference; lastKnownFileType = audio.midi; path = music.mid; sourceTree = ""; }; - 1AD263B71683506C0089000C /* Particles */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Particles; sourceTree = ""; }; - 1AD263B81683506C0089000C /* Shaders */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Shaders; sourceTree = ""; }; - 1AD263B91683506C0089000C /* TileMaps */ = {isa = PBXFileReference; lastKnownFileType = folder; path = TileMaps; sourceTree = ""; }; - 1AD263BA1683506C0089000C /* zwoptex */ = {isa = PBXFileReference; lastKnownFileType = folder; path = zwoptex; sourceTree = ""; }; - F293B3C815EB7BE500256477 /* TestLua.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestLua.app; sourceTree = BUILT_PRODUCTS_DIR; }; - F293B3CC15EB7BE500256477 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - F293B3CE15EB7BE500256477 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; - F293B3D015EB7BE500256477 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; - F293B3D215EB7BE500256477 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; - F293B3D415EB7BE500256477 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - F293B3D615EB7BE500256477 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - F293B3D815EB7BE500256477 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - F293B3DA15EB7BE500256477 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - F293B6F615EB823D00256477 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; - F293B6F715EB823D00256477 /* AppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppController.mm; sourceTree = ""; }; - F293B6F815EB823D00256477 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - F293B6F915EB823D00256477 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; - F293B6FA15EB823D00256477 /* RootViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RootViewController.mm; sourceTree = ""; }; - F293B6FB15EB823D00256477 /* TestLua_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestLua_Prefix.pch; sourceTree = ""; }; - F293BB7E15EB831F00256477 /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AppDelegate.cpp; path = ../Classes/AppDelegate.cpp; sourceTree = ""; }; - F293BB7F15EB831F00256477 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ../Classes/AppDelegate.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - F293B3C515EB7BE500256477 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A6E48E817781C2B0055514D /* libBox2D.a in Frameworks */, - 1A6E48E917781C2B0055514D /* libchipmunk.a in Frameworks */, - 1A6E48EA17781C2B0055514D /* libcocos2dx.a in Frameworks */, - 1A6E48EB17781C2B0055514D /* libCocosDenshion.a in Frameworks */, - 1A6E4900177821AF0055514D /* libextensions.a in Frameworks */, - 1A6E48ED17781C2B0055514D /* libluabindings.a in Frameworks */, - F293B3CD15EB7BE500256477 /* QuartzCore.framework in Frameworks */, - F293B3CF15EB7BE500256477 /* OpenGLES.framework in Frameworks */, - F293B3D115EB7BE500256477 /* OpenAL.framework in Frameworks */, - F293B3D315EB7BE500256477 /* AudioToolbox.framework in Frameworks */, - F293B3D515EB7BE500256477 /* AVFoundation.framework in Frameworks */, - F293B3D715EB7BE500256477 /* UIKit.framework in Frameworks */, - F293B3D915EB7BE500256477 /* Foundation.framework in Frameworks */, - F293B3DB15EB7BE500256477 /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1A6E48F617781F9F0055514D /* script */ = { - isa = PBXGroup; - children = ( - 1A6E48F717781F9F0055514D /* AudioEngine.lua */, - 1A6E48F817781F9F0055514D /* CCBReaderLoad.lua */, - 1A6E48F917781F9F0055514D /* Cocos2dConstants.lua */, - 1A6E48FA17781F9F0055514D /* OpenglConstants.lua */, - ); - name = script; - path = ../../../../scripting/lua/script; - sourceTree = ""; - }; - F293B3BD15EB7BE500256477 = { - isa = PBXGroup; - children = ( - F293BB7C15EB830F00256477 /* Classes */, - F293B3CB15EB7BE500256477 /* Frameworks */, - F293B6E815EB807E00256477 /* Other Sources */, - F293B3C915EB7BE500256477 /* Products */, - F293BC4615EB859D00256477 /* Resources */, - ); - sourceTree = ""; - }; - F293B3C915EB7BE500256477 /* Products */ = { - isa = PBXGroup; - children = ( - F293B3C815EB7BE500256477 /* TestLua.app */, - ); - name = Products; - sourceTree = ""; - }; - F293B3CB15EB7BE500256477 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1A6E48E217781C2B0055514D /* libBox2D.a */, - 1A6E48E317781C2B0055514D /* libchipmunk.a */, - 1A6E48E417781C2B0055514D /* libcocos2dx.a */, - 1A6E48E517781C2B0055514D /* libCocosDenshion.a */, - 1A6E48FF177821AF0055514D /* libextensions.a */, - 1A6E48E717781C2B0055514D /* libluabindings.a */, - F293B3CC15EB7BE500256477 /* QuartzCore.framework */, - F293B3CE15EB7BE500256477 /* OpenGLES.framework */, - F293B3D015EB7BE500256477 /* OpenAL.framework */, - F293B3D215EB7BE500256477 /* AudioToolbox.framework */, - F293B3D415EB7BE500256477 /* AVFoundation.framework */, - F293B3D615EB7BE500256477 /* UIKit.framework */, - F293B3D815EB7BE500256477 /* Foundation.framework */, - F293B3DA15EB7BE500256477 /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - F293B6E815EB807E00256477 /* Other Sources */ = { - isa = PBXGroup; - children = ( - F293B6F615EB823D00256477 /* AppController.h */, - F293B6F715EB823D00256477 /* AppController.mm */, - F293B6F815EB823D00256477 /* main.m */, - F293B6F915EB823D00256477 /* RootViewController.h */, - F293B6FA15EB823D00256477 /* RootViewController.mm */, - F293B6FB15EB823D00256477 /* TestLua_Prefix.pch */, - ); - name = "Other Sources"; - sourceTree = ""; - }; - F293BB7C15EB830F00256477 /* Classes */ = { - isa = PBXGroup; - children = ( - F293BB7E15EB831F00256477 /* AppDelegate.cpp */, - F293BB7F15EB831F00256477 /* AppDelegate.h */, - ); - name = Classes; - sourceTree = ""; - }; - F293BC4615EB859D00256477 /* Resources */ = { - isa = PBXGroup; - children = ( - 1A6E48F617781F9F0055514D /* script */, - 159B8A27175D9A930005B47D /* cocosbuilderRes */, - 1AD263A31683506C0089000C /* animations */, - 1AD263A41683506C0089000C /* app.icf */, - 1AD263A51683506C0089000C /* background.mp3 */, - 1AD263A61683506C0089000C /* background.ogg */, - 1AD263A71683506C0089000C /* ccb */, - 1AD263A81683506C0089000C /* CocosBuilderExample.ccbproj */, - 1AD263A91683506C0089000C /* CocosBuilderExample.ccbresourcelog */, - 1AD263AA1683506C0089000C /* development.icf */, - 1AD263AB1683506C0089000C /* effect1.raw */, - 1AD263AC1683506C0089000C /* effect1.wav */, - 1AD263AD1683506C0089000C /* effect2.ogg */, - 1AD263AE1683506C0089000C /* extensions */, - 1AD263AF1683506C0089000C /* fonts */, - 1AD263B01683506C0089000C /* fps_images.png */, - 1AD263B11683506C0089000C /* hd */, - 1AD263B21683506C0089000C /* Hello.png */, - 1AD263B31683506C0089000C /* Images */, - 1AD263B41683506C0089000C /* ipad */, - 1AD263B51683506C0089000C /* ipadhd */, - 1AD263B61683506C0089000C /* music.mid */, - 1AD263B71683506C0089000C /* Particles */, - 1AD263B81683506C0089000C /* Shaders */, - 1AD263B91683506C0089000C /* TileMaps */, - 1AD263BA1683506C0089000C /* zwoptex */, - 1AD263A1168350490089000C /* luaScript */, - 15C156911683138E00D239F2 /* Default-568h@2x.png */, - 15C156921683138E00D239F2 /* Default.png */, - 15C156931683138E00D239F2 /* Default@2x.png */, - 15C156941683138E00D239F2 /* Icon-57.png */, - 15C156951683138E00D239F2 /* Icon-72.png */, - 15C156961683138E00D239F2 /* Icon-114.png */, - 15C156971683138E00D239F2 /* Icon-144.png */, - ); - name = Resources; - path = ../../../Cpp/TestCpp/Resources; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - F293B3C715EB7BE500256477 /* TestLua */ = { - isa = PBXNativeTarget; - buildConfigurationList = F293B6C415EB7BEA00256477 /* Build configuration list for PBXNativeTarget "TestLua" */; - buildPhases = ( - F293B3C415EB7BE500256477 /* Sources */, - F293B3C515EB7BE500256477 /* Frameworks */, - F293B3C615EB7BE500256477 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = TestLua; - productName = TestLua; - productReference = F293B3C815EB7BE500256477 /* TestLua.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - F293B3BF15EB7BE500256477 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0430; - }; - buildConfigurationList = F293B3C215EB7BE500256477 /* Build configuration list for PBXProject "TestLua" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = F293B3BD15EB7BE500256477; - productRefGroup = F293B3C915EB7BE500256477 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - F293B3C715EB7BE500256477 /* TestLua */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - F293B3C615EB7BE500256477 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 15C156981683138E00D239F2 /* Default-568h@2x.png in Resources */, - 15C156991683138E00D239F2 /* Default.png in Resources */, - 15C1569A1683138E00D239F2 /* Default@2x.png in Resources */, - 15C1569B1683138E00D239F2 /* Icon-57.png in Resources */, - 15C1569C1683138E00D239F2 /* Icon-72.png in Resources */, - 15C1569D1683138E00D239F2 /* Icon-114.png in Resources */, - 15C1569E1683138E00D239F2 /* Icon-144.png in Resources */, - 1AD263A2168350490089000C /* luaScript in Resources */, - 1AD263BB1683506D0089000C /* animations in Resources */, - 1AD263BC1683506D0089000C /* app.icf in Resources */, - 1AD263BD1683506D0089000C /* background.mp3 in Resources */, - 1AD263BE1683506D0089000C /* background.ogg in Resources */, - 1AD263BF1683506D0089000C /* ccb in Resources */, - 1AD263C01683506D0089000C /* CocosBuilderExample.ccbproj in Resources */, - 1AD263C11683506D0089000C /* CocosBuilderExample.ccbresourcelog in Resources */, - 1AD263C21683506D0089000C /* development.icf in Resources */, - 1AD263C31683506D0089000C /* effect1.raw in Resources */, - 1AD263C41683506D0089000C /* effect1.wav in Resources */, - 1AD263C51683506D0089000C /* effect2.ogg in Resources */, - 1AD263C61683506D0089000C /* extensions in Resources */, - 1AD263C71683506D0089000C /* fonts in Resources */, - 1AD263C81683506D0089000C /* fps_images.png in Resources */, - 1AD263C91683506D0089000C /* hd in Resources */, - 1AD263CA1683506D0089000C /* Hello.png in Resources */, - 1AD263CB1683506D0089000C /* Images in Resources */, - 1AD263CC1683506D0089000C /* ipad in Resources */, - 1AD263CD1683506D0089000C /* ipadhd in Resources */, - 1AD263CE1683506D0089000C /* music.mid in Resources */, - 1AD263CF1683506D0089000C /* Particles in Resources */, - 1AD263D01683506D0089000C /* Shaders in Resources */, - 1AD263D11683506D0089000C /* TileMaps in Resources */, - 1AD263D21683506D0089000C /* zwoptex in Resources */, - 159B8A28175D9A930005B47D /* cocosbuilderRes in Resources */, - 1A6E48FB17781F9F0055514D /* AudioEngine.lua in Resources */, - 1A6E48FC17781F9F0055514D /* CCBReaderLoad.lua in Resources */, - 1A6E48FD17781F9F0055514D /* Cocos2dConstants.lua in Resources */, - 1A6E48FE17781F9F0055514D /* OpenglConstants.lua in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - F293B3C415EB7BE500256477 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - F293B6FC15EB823D00256477 /* AppController.mm in Sources */, - F293B6FD15EB823D00256477 /* main.m in Sources */, - F293B6FE15EB823D00256477 /* RootViewController.mm in Sources */, - F293BB9C15EB831F00256477 /* AppDelegate.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - F293B6C215EB7BEA00256477 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - DEBUG, - "COCOS2D_DEBUG=1", - USE_FILE32API, - TARGET_OS_IPHONE, - "CC_LUA_ENGINE_ENABLED=1", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - "\"$(PROJECT_NAME)/libs/cocos2dx/kazmath/include\"", - "\"$(PROJECT_NAME)/libs/cocos2dx\"", - "\"$(PROJECT_NAME)/libs/CocosDenshion/include\"", - "\"$(SDKROOT)/usr/include/libxml2\"", - "\"$(SRCROOT)/../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../external/lua/tolua\"", - "\"$(SRCROOT)/../../../external/lua/src\"", - "$(SRCROOT)/../../../external/lua/cocos2dx_support", - "$(SRCROOT)/../../../cocos2dx/platform/ios", - "$(SRCROOT)/../../../cocos2dx/include", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.1; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - SDKROOT = iphoneos; - }; - name = Debug; - }; - F293B6C315EB7BEA00256477 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_PREPROCESSOR_DEFINITIONS = ( - NDEBUG, - USE_FILE32API, - TARGET_OS_IPHONE, - "CC_LUA_ENGINE_ENABLED=1", - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - "\"$(PROJECT_NAME)/libs/cocos2dx/kazmath/include\"", - "\"$(PROJECT_NAME)/libs/cocos2dx\"", - "\"$(PROJECT_NAME)/libs/CocosDenshion/include\"", - "\"$(SDKROOT)/usr/include/libxml2\"", - "\"$(SRCROOT)/../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../external/lua/tolua\"", - "\"$(SRCROOT)/../../../external/lua/src\"", - "$(SRCROOT)/../../../external/lua/cocos2dx_support", - "$(SRCROOT)/../../../cocos2dx/platform/ios", - "$(SRCROOT)/../../../cocos2dx/include", - ); - IPHONEOS_DEPLOYMENT_TARGET = 5.1; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - SDKROOT = iphoneos; - }; - name = Release; - }; - F293B6C515EB7BEA00256477 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TestLua_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - DEBUG, - "COCOS2D_DEBUG=1", - USE_FILE32API, - CC_TARGET_OS_IPHONE, - "CC_LUA_ENGINE_ENABLED=1", - "CC_ENABLE_BOX2D_INTEGRATION=1", - ); - "GCC_THUMB_SUPPORT[arch=armv6]" = ""; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../CocosDenshion/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/cocos2dx_support\"", - "\"$(SRCROOT)/../../../../scripting/lua/luajit/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/tolua\"", - ); - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios/libraries", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lz"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - F293B6C615EB7BEA00256477 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TestLua_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - NDEBUG, - USE_FILE32API, - CC_TARGET_OS_IPHONE, - "CC_LUA_ENGINE_ENABLED=1", - "CC_ENABLE_BOX2D_INTEGRATION=1", - ); - "GCC_THUMB_SUPPORT[arch=armv6]" = ""; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../../../cocos2dx/\"", - "\"$(SRCROOT)/../../../../cocos2dx/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/kazmath/include\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/ios\"", - "\"$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios\"", - "\"$(SRCROOT)/../../../../CocosDenshion/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/cocos2dx_support\"", - "\"$(SRCROOT)/../../../../scripting/lua/luajit/include\"", - "\"$(SRCROOT)/../../../../scripting/lua/tolua\"", - ); - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../../../../cocos2dx/platform/third_party/ios/libraries", - ); - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lz"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - F293B3C215EB7BE500256477 /* Build configuration list for PBXProject "TestLua" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F293B6C215EB7BEA00256477 /* Debug */, - F293B6C315EB7BEA00256477 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - F293B6C415EB7BEA00256477 /* Build configuration list for PBXNativeTarget "TestLua" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F293B6C515EB7BEA00256477 /* Debug */, - F293B6C615EB7BEA00256477 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = F293B3BF15EB7BE500256477 /* Project object */; -} From 8eeb911e8f4df475d041341f35d94c30204751fe Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 15:25:45 +0800 Subject: [PATCH 115/116] issue #2905: adjust folder structure --- cocos/base/CCPlatformConfig.h | 140 ++ cocos/base/CCPlatformMacros.h | 301 ++++ cocos/base/atitc/atitc.cpp | 195 +++ cocos/base/atitc/atitc.h | 48 + cocos/base/cocoa/CCAffineTransform.cpp | 132 ++ cocos/base/cocoa/CCAffineTransform.h | 63 + cocos/base/cocoa/CCArray.cpp | 754 +++++++++ cocos/base/cocoa/CCArray.h | 557 ++++++ cocos/base/cocoa/CCAutoreleasePool.cpp | 204 +++ cocos/base/cocoa/CCAutoreleasePool.h | 181 ++ cocos/base/cocoa/CCBool.h | 70 + cocos/base/cocoa/CCData.cpp | 61 + cocos/base/cocoa/CCData.h | 88 + cocos/base/cocoa/CCDataVisitor.cpp | 240 +++ cocos/base/cocoa/CCDataVisitor.h | 117 ++ cocos/base/cocoa/CCDictionary.cpp | 454 +++++ cocos/base/cocoa/CCDictionary.h | 458 +++++ cocos/base/cocoa/CCDouble.h | 70 + cocos/base/cocoa/CCFloat.h | 71 + cocos/base/cocoa/CCGeometry.cpp | 463 +++++ cocos/base/cocoa/CCGeometry.h | 564 +++++++ cocos/base/cocoa/CCInteger.h | 79 + cocos/base/cocoa/CCNS.cpp | 185 ++ cocos/base/cocoa/CCNS.h | 80 + cocos/base/cocoa/CCObject.cpp | 93 + cocos/base/cocoa/CCObject.h | 216 +++ cocos/base/cocoa/CCSet.cpp | 166 ++ cocos/base/cocoa/CCSet.h | 119 ++ cocos/base/cocoa/CCString.cpp | 277 +++ cocos/base/cocoa/CCString.h | 210 +++ cocos/base/etc1/etc1.cpp | 670 ++++++++ cocos/base/etc1/etc1.h | 106 ++ cocos/base/s3tc/s3tc.cpp | 182 ++ cocos/base/s3tc/s3tc.h | 48 + external/tinyxml2/tinyxml2.cpp | 2101 +++++++++++++++++++++++ external/tinyxml2/tinyxml2.h | 1914 +++++++++++++++++++++ external/unzip/ioapi.cpp | 245 +++ external/unzip/ioapi.h | 201 +++ external/unzip/unzip.cpp | 2161 ++++++++++++++++++++++++ external/unzip/unzip.h | 455 +++++ 40 files changed, 14739 insertions(+) create mode 100644 cocos/base/CCPlatformConfig.h create mode 100644 cocos/base/CCPlatformMacros.h create mode 100644 cocos/base/atitc/atitc.cpp create mode 100644 cocos/base/atitc/atitc.h create mode 100644 cocos/base/cocoa/CCAffineTransform.cpp create mode 100644 cocos/base/cocoa/CCAffineTransform.h create mode 100644 cocos/base/cocoa/CCArray.cpp create mode 100644 cocos/base/cocoa/CCArray.h create mode 100644 cocos/base/cocoa/CCAutoreleasePool.cpp create mode 100644 cocos/base/cocoa/CCAutoreleasePool.h create mode 100644 cocos/base/cocoa/CCBool.h create mode 100644 cocos/base/cocoa/CCData.cpp create mode 100644 cocos/base/cocoa/CCData.h create mode 100644 cocos/base/cocoa/CCDataVisitor.cpp create mode 100644 cocos/base/cocoa/CCDataVisitor.h create mode 100644 cocos/base/cocoa/CCDictionary.cpp create mode 100644 cocos/base/cocoa/CCDictionary.h create mode 100644 cocos/base/cocoa/CCDouble.h create mode 100644 cocos/base/cocoa/CCFloat.h create mode 100644 cocos/base/cocoa/CCGeometry.cpp create mode 100644 cocos/base/cocoa/CCGeometry.h create mode 100644 cocos/base/cocoa/CCInteger.h create mode 100644 cocos/base/cocoa/CCNS.cpp create mode 100644 cocos/base/cocoa/CCNS.h create mode 100644 cocos/base/cocoa/CCObject.cpp create mode 100644 cocos/base/cocoa/CCObject.h create mode 100644 cocos/base/cocoa/CCSet.cpp create mode 100644 cocos/base/cocoa/CCSet.h create mode 100644 cocos/base/cocoa/CCString.cpp create mode 100644 cocos/base/cocoa/CCString.h create mode 100644 cocos/base/etc1/etc1.cpp create mode 100644 cocos/base/etc1/etc1.h create mode 100644 cocos/base/s3tc/s3tc.cpp create mode 100644 cocos/base/s3tc/s3tc.h create mode 100644 external/tinyxml2/tinyxml2.cpp create mode 100644 external/tinyxml2/tinyxml2.h create mode 100644 external/unzip/ioapi.cpp create mode 100644 external/unzip/ioapi.h create mode 100644 external/unzip/unzip.cpp create mode 100644 external/unzip/unzip.h diff --git a/cocos/base/CCPlatformConfig.h b/cocos/base/CCPlatformConfig.h new file mode 100644 index 0000000000..5ba0757dac --- /dev/null +++ b/cocos/base/CCPlatformConfig.h @@ -0,0 +1,140 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CC_PLATFORM_CONFIG_H__ +#define __CC_PLATFORM_CONFIG_H__ + +/** +Config of cocos2d-x project, per target platform. +*/ + +////////////////////////////////////////////////////////////////////////// +// pre configure +////////////////////////////////////////////////////////////////////////// + +// define supported target platform macro which CC uses. +#define CC_PLATFORM_UNKNOWN 0 +#define CC_PLATFORM_IOS 1 +#define CC_PLATFORM_ANDROID 2 +#define CC_PLATFORM_WIN32 3 +#define CC_PLATFORM_MARMALADE 4 +#define CC_PLATFORM_LINUX 5 +#define CC_PLATFORM_BADA 6 +#define CC_PLATFORM_BLACKBERRY 7 +#define CC_PLATFORM_MAC 8 +#define CC_PLATFORM_NACL 9 +#define CC_PLATFORM_EMSCRIPTEN 10 +#define CC_PLATFORM_TIZEN 11 +#define CC_PLATFORM_QT5 12 + +// Determine target platform by compile environment macro. +#define CC_TARGET_PLATFORM CC_PLATFORM_UNKNOWN + +// mac +#if defined(CC_TARGET_OS_MAC) +#undef CC_TARGET_PLATFORM +#define CC_TARGET_PLATFORM CC_PLATFORM_MAC +#endif + +// iphone +#if defined(CC_TARGET_OS_IPHONE) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_IOS +#endif + +// android +#if defined(ANDROID) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_ANDROID +#endif + +// win32 +#if defined(WIN32) && defined(_WINDOWS) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_WIN32 +#endif + +// linux +#if defined(LINUX) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_LINUX +#endif + +// marmalade +#if defined(MARMALADE) +#undef CC_TARGET_PLATFORM +#define CC_TARGET_PLATFORM CC_PLATFORM_MARMALADE +#endif + +// bada +#if defined(SHP) +#undef CC_TARGET_PLATFORM +#define CC_TARGET_PLATFORM CC_PLATFORM_BADA +#endif + +// qnx +#if defined(__QNX__) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_BLACKBERRY +#endif + +// native client +#if defined(__native_client__) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_NACL +#endif + +// Emscripten +#if defined(EMSCRIPTEN) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_EMSCRIPTEN +#endif + +// tizen +#if defined(TIZEN) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_TIZEN +#endif + +// qt5 +#if defined(CC_TARGET_QT5) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_QT5 +#endif + +////////////////////////////////////////////////////////////////////////// +// post configure +////////////////////////////////////////////////////////////////////////// + +// check user set platform +#if ! CC_TARGET_PLATFORM + #error "Cannot recognize the target platform; are you targeting an unsupported platform?" +#endif + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) +#pragma warning (disable:4127) +#endif // CC_PLATFORM_WIN32 + +#endif // __CC_PLATFORM_CONFIG_H__ + diff --git a/cocos/base/CCPlatformMacros.h b/cocos/base/CCPlatformMacros.h new file mode 100644 index 0000000000..fca1255c0d --- /dev/null +++ b/cocos/base/CCPlatformMacros.h @@ -0,0 +1,301 @@ +/**************************************************************************** + Copyright (c) 2010 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#ifndef __CC_PLATFORM_MACROS_H__ +#define __CC_PLATFORM_MACROS_H__ + +/** + * define some platform specific macros + */ +#include "ccConfig.h" +#include "CCPlatformConfig.h" +#include "CCPlatformDefine.h" + +/** + * define a create function for a specific type, such as Layer + * @param \__TYPE__ class type to add create(), such as Layer + */ +#define CREATE_FUNC(__TYPE__) \ +static __TYPE__* create() \ +{ \ + __TYPE__ *pRet = new __TYPE__(); \ + if (pRet && pRet->init()) \ + { \ + pRet->autorelease(); \ + return pRet; \ + } \ + else \ + { \ + delete pRet; \ + pRet = NULL; \ + return NULL; \ + } \ +} + +/** + * define a node function for a specific type, such as Layer + * @param \__TYPE__ class type to add node(), such as Layer + * @deprecated This interface will be deprecated sooner or later. + */ +#define NODE_FUNC(__TYPE__) \ +CC_DEPRECATED_ATTRIBUTE static __TYPE__* node() \ +{ \ + __TYPE__ *pRet = new __TYPE__(); \ + if (pRet && pRet->init()) \ + { \ + pRet->autorelease(); \ + return pRet; \ + } \ + else \ + { \ + delete pRet; \ + pRet = NULL; \ + return NULL; \ + } \ +} + +/** @def CC_ENABLE_CACHE_TEXTURE_DATA +Enable it if you want to cache the texture data. +Not enabling for Emscripten any more -- doesn't seem necessary and don't want +to be different from other platforms unless there's a good reason. + +It's new in cocos2d-x since v0.99.5 +*/ +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + #define CC_ENABLE_CACHE_TEXTURE_DATA 1 +#else + #define CC_ENABLE_CACHE_TEXTURE_DATA 0 +#endif + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_EMSCRIPTEN) + /* Application will crash in glDrawElements function on some win32 computers and some android devices. + Indices should be bound again while drawing to avoid this bug. + */ + #define CC_REBIND_INDICES_BUFFER 1 +#else + #define CC_REBIND_INDICES_BUFFER 0 +#endif + +// generic macros + +// namespace cocos2d {} +#ifdef __cplusplus + #define NS_CC_BEGIN namespace cocos2d { + #define NS_CC_END } + #define USING_NS_CC using namespace cocos2d +#else + #define NS_CC_BEGIN + #define NS_CC_END + #define USING_NS_CC +#endif + +/** CC_PROPERTY_READONLY is used to declare a protected variable. + We can use getter to read the variable. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + @warning The getter is a public virtual function, you should rewrite it first. + The variables and methods declared after CC_PROPERTY_READONLY are all public. + If you need protected or private, please declare. + */ +#define CC_PROPERTY_READONLY(varType, varName, funName)\ +protected: varType varName;\ +public: virtual varType get##funName(void) const; + +#define CC_PROPERTY_READONLY_PASS_BY_REF(varType, varName, funName)\ +protected: varType varName;\ +public: virtual const varType& get##funName(void) const; + +/** CC_PROPERTY is used to declare a protected variable. + We can use getter to read the variable, and use the setter to change the variable. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + "set + funName" will be the name of the setter. + @warning The getter and setter are public virtual functions, you should rewrite them first. + The variables and methods declared after CC_PROPERTY are all public. + If you need protected or private, please declare. + */ +#define CC_PROPERTY(varType, varName, funName)\ +protected: varType varName;\ +public: virtual varType get##funName(void);\ +public: virtual void set##funName(varType var); + +#define CC_PROPERTY_PASS_BY_REF(varType, varName, funName)\ +protected: varType varName;\ +public: virtual const varType& get##funName(void) const;\ +public: virtual void set##funName(const varType& var); + +/** CC_SYNTHESIZE_READONLY is used to declare a protected variable. + We can use getter to read the variable. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + @warning The getter is a public inline function. + The variables and methods declared after CC_SYNTHESIZE_READONLY are all public. + If you need protected or private, please declare. + */ +#define CC_SYNTHESIZE_READONLY(varType, varName, funName)\ +protected: varType varName;\ +public: virtual varType get##funName(void) const { return varName; } + +#define CC_SYNTHESIZE_READONLY_PASS_BY_REF(varType, varName, funName)\ +protected: varType varName;\ +public: virtual const varType& get##funName(void) const { return varName; } + +/** CC_SYNTHESIZE is used to declare a protected variable. + We can use getter to read the variable, and use the setter to change the variable. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + "set + funName" will be the name of the setter. + @warning The getter and setter are public inline functions. + The variables and methods declared after CC_SYNTHESIZE are all public. + If you need protected or private, please declare. + */ +#define CC_SYNTHESIZE(varType, varName, funName)\ +protected: varType varName;\ +public: virtual varType get##funName(void) const { return varName; }\ +public: virtual void set##funName(varType var){ varName = var; } + +#define CC_SYNTHESIZE_PASS_BY_REF(varType, varName, funName)\ +protected: varType varName;\ +public: virtual const varType& get##funName(void) const { return varName; }\ +public: virtual void set##funName(const varType& var){ varName = var; } + +#define CC_SYNTHESIZE_RETAIN(varType, varName, funName) \ +private: varType varName; \ +public: virtual varType get##funName(void) const { return varName; } \ +public: virtual void set##funName(varType var) \ +{ \ + if (varName != var) \ + { \ + CC_SAFE_RETAIN(var); \ + CC_SAFE_RELEASE(varName); \ + varName = var; \ + } \ +} + +#define CC_SAFE_DELETE(p) do { delete (p); (p) = nullptr; } while(0) +#define CC_SAFE_DELETE_ARRAY(p) do { if(p) { delete[] (p); (p) = nullptr; } } while(0) +#define CC_SAFE_FREE(p) do { if(p) { free(p); (p) = nullptr; } } while(0) +#define CC_SAFE_RELEASE(p) do { if(p) { (p)->release(); } } while(0) +#define CC_SAFE_RELEASE_NULL(p) do { if(p) { (p)->release(); (p) = nullptr; } } while(0) +#define CC_SAFE_RETAIN(p) do { if(p) { (p)->retain(); } } while(0) +#define CC_BREAK_IF(cond) if(cond) break + +#define __CCLOGWITHFUNCTION(s, ...) \ + log("%s : %s",__FUNCTION__, String::createWithFormat(s, ##__VA_ARGS__)->getCString()) + +// cocos2d debug +#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 +#define CCLOG(...) do {} while (0) +#define CCLOGINFO(...) do {} while (0) +#define CCLOGERROR(...) do {} while (0) +#define CCLOGWARN(...) do {} while (0) + +#elif COCOS2D_DEBUG == 1 +#define CCLOG(format, ...) cocos2d::log(format, ##__VA_ARGS__) +#define CCLOGERROR(format,...) cocos2d::log(format, ##__VA_ARGS__) +#define CCLOGINFO(format,...) do {} while (0) +#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) + +#elif COCOS2D_DEBUG > 1 +#define CCLOG(format, ...) cocos2d::log(format, ##__VA_ARGS__) +#define CCLOGERROR(format,...) cocos2d::log(format, ##__VA_ARGS__) +#define CCLOGINFO(format,...) cocos2d::log(format, ##__VA_ARGS__) +#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) +#endif // COCOS2D_DEBUG + +// Lua engine debug +#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 || CC_LUA_ENGINE_DEBUG == 0 +#define LUALOG(...) +#else +#define LUALOG(format, ...) cocos2d::log(format, ##__VA_ARGS__) +#endif // Lua engine debug + +#if defined(__GNUC__) && ((__GNUC__ >= 5) || ((__GNUG__ == 4) && (__GNUC_MINOR__ >= 4))) \ + || (defined(__clang__) && (__clang_major__ >= 3)) +#define CC_DISABLE_COPY(Class) \ +private: \ + Class(const Class &) = delete; \ + Class &operator =(const Class &) = delete; +#else +#define CC_DISABLE_COPY(Class) \ +private: \ + Class(const Class &); \ + Class &operator =(const Class &); +#endif + +/* + * only certain compilers support __attribute__((deprecated)) + */ +#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) + #define CC_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#elif _MSC_VER >= 1400 //vs 2005 or higher + #define CC_DEPRECATED_ATTRIBUTE __declspec(deprecated) +#else + #define CC_DEPRECATED_ATTRIBUTE +#endif + +/* + * only certain compiler support __attribute__((format)) + * formatPos - 1-based position of format string argument + * argPos - 1-based position of first format-dependent argument + */ +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define CC_FORMAT_PRINTF(formatPos, argPos) __attribute__((__format__(printf, formatPos, argPos))) +#elif defined(__has_attribute) + #if __has_attribute(format) + #define CC_FORMAT_PRINTF(formatPos, argPos) __attribute__((__format__(printf, formatPos, argPos))) + #endif // __has_attribute(format) +#else +#define CC_FORMAT_PRINTF(formatPos, argPos) +#endif + +#if defined(_MSC_VER) +#define CC_FORMAT_PRINTF_SIZE_T "%08lX" +#else +#define CC_FORMAT_PRINTF_SIZE_T "%08zX" +#endif + +#ifdef __GNUC__ +#define CC_UNUSED __attribute__ ((unused)) +#else +#define CC_UNUSED +#endif + +// +// CC_REQUIRES_NULL_TERMINATION +// +#if !defined(CC_REQUIRES_NULL_TERMINATION) + #if defined(__APPLE_CC__) && (__APPLE_CC__ >= 5549) + #define CC_REQUIRES_NULL_TERMINATION __attribute__((sentinel(0,1))) + #elif defined(__GNUC__) + #define CC_REQUIRES_NULL_TERMINATION __attribute__((sentinel)) + #else + #define CC_REQUIRES_NULL_TERMINATION + #endif +#endif + +#endif // __CC_PLATFORM_MACROS_H__ diff --git a/cocos/base/atitc/atitc.cpp b/cocos/base/atitc/atitc.cpp new file mode 100644 index 0000000000..3a60d6d2f7 --- /dev/null +++ b/cocos/base/atitc/atitc.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "atitc.h" + +//Decode ATITC encode block to 4x4 RGB32 pixels +static void atitc_decode_block(uint8_t **blockData, + uint32_t *decodeBlockData, + unsigned int stride, + bool oneBitAlphaFlag, + uint64_t alpha, + ATITCDecodeFlag decodeFlag) +{ + unsigned int colorValue0 = 0 , colorValue1 = 0, initAlpha = (!oneBitAlphaFlag * 255u) << 24; + unsigned int rb0 = 0, rb1 = 0, rb2 = 0, rb3 = 0, g0 = 0, g1 = 0, g2 = 0, g3 = 0; + bool msb = 0; + + uint32_t colors[4], pixelsIndex = 0; + + /* load the two color values*/ + memcpy((void *)&colorValue0, *blockData, 2); + (*blockData) += 2; + + memcpy((void *)&colorValue1, *blockData, 2); + (*blockData) += 2; + + //extract the msb flag + msb = (colorValue0 & 0x8000) != 0; + + /* the channel is r5g6b5 , 16 bits */ + rb0 = (colorValue0 << 3 | colorValue0 << 9) & 0xf800f8; + rb1 = (colorValue1 << 3 | colorValue1 << 8) & 0xf800f8; + g0 = (colorValue0 << 6) & 0x00fc00; + g1 = (colorValue1 << 5) & 0x00fc00; + g0 += (g0 >> 6) & 0x000300; + g1 += (g1 >> 6) & 0x000300; + + /* interpolate the other two color values */ + if (!msb) + { + colors[0] = rb0 + g0 + initAlpha; + colors[3] = rb1 + g1 + initAlpha; + + rb2 = (((2*rb0 + rb1) * 21) >> 6) & 0xff00ff; + rb3 = (((2*rb1 + rb0) * 21) >> 6) & 0xff00ff; + g2 = (((2*g0 + g1 ) * 21) >> 6) & 0x00ff00; + g3 = (((2*g1 + g0 ) * 21) >> 6) & 0x00ff00; + + colors[2] = rb3 + g3 + initAlpha; + colors[1] = rb2 + g2 + initAlpha; + } + else + { + colors[2] = rb0 + g0 + initAlpha; + colors[3] = rb1 + g1 + initAlpha; + + rb2 = (rb0 - (rb1 >> 2)) & 0xff00ff; + g2 = (g0 - (g1 >> 2)) & 0x00ff00; + colors[0] = 0 ; + + colors[1] = rb2 + g2 + initAlpha; + } + + /*read the pixelsIndex , 2bits per pixel, 4 bytes */ + memcpy((void*)&pixelsIndex, *blockData, 4); + (*blockData) += 4; + + if (ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA == decodeFlag) + { + // atitc_interpolated_alpha use interpolate alpha + // 8-Alpha block: derive the other six alphas. + // Bit code 000 = alpha0, 001 = alpha1, other are interpolated. + + unsigned int alphaArray[8]; + + alphaArray[0] = (alpha ) & 0xff ; + alphaArray[1] = (alpha >> 8) & 0xff ; + + if (alphaArray[0] >= alphaArray[1]) + { + alphaArray[2] = (alphaArray[0]*6 + alphaArray[1]*1) / 7; + alphaArray[3] = (alphaArray[0]*5 + alphaArray[1]*2) / 7; + alphaArray[4] = (alphaArray[0]*4 + alphaArray[1]*3) / 7; + alphaArray[5] = (alphaArray[0]*3 + alphaArray[1]*4) / 7; + alphaArray[6] = (alphaArray[0]*2 + alphaArray[1]*5) / 7; + alphaArray[7] = (alphaArray[0]*1 + alphaArray[1]*6) / 7; + } + else if (alphaArray[0] < alphaArray[1]) + { + alphaArray[2] = (alphaArray[0]*4 + alphaArray[1]*1) / 5; + alphaArray[3] = (alphaArray[0]*3 + alphaArray[1]*2) / 5; + alphaArray[4] = (alphaArray[0]*2 + alphaArray[1]*3) / 5; + alphaArray[5] = (alphaArray[0]*1 + alphaArray[1]*4) / 5; + alphaArray[6] = 0; + alphaArray[7] = 255; + } + + // read the flowing 48bit indices (16*3) + alpha >>= 16; + + for (int y = 0; y < 4; ++y) + { + for (int x = 0; x < 4; ++x) + { + decodeBlockData[x] = (alphaArray[alpha & 5] << 24) + colors[pixelsIndex & 3]; + pixelsIndex >>= 2; + alpha >>= 3; + } + decodeBlockData += stride; + } + } //if (atc_interpolated_alpha == comFlag) + else + { + /* atc_rgb atc_explicit_alpha use explicit alpha */ + + for (int y = 0; y < 4; ++y) + { + for (int x = 0; x < 4; ++x) + { + initAlpha = (alpha & 0x0f) << 28; + initAlpha += initAlpha >> 4; + decodeBlockData[x] = initAlpha + colors[pixelsIndex & 3]; + pixelsIndex >>= 2; + alpha >>= 4; + } + decodeBlockData += stride; + } + } +} + +//Decode ATITC encode data to RGB32 +void atitc_decode(uint8_t *encodeData, //in_data + uint8_t *decodeData, //out_data + const int pixelsWidth, + const int pixelsHeight, + ATITCDecodeFlag decodeFlag) +{ + uint32_t *decodeBlockData = (uint32_t *)decodeData; + + for (int block_y = 0; block_y < pixelsHeight / 4; ++block_y, decodeBlockData += 3 * pixelsWidth) //stride = 3*width + { + for (int block_x = 0; block_x < pixelsWidth / 4; ++block_x, decodeBlockData += 4) //skip 4 pixels + { + uint64_t blockAlpha = 0; + + switch (decodeFlag) + { + case ATITCDecodeFlag::ATC_RGB: + { + atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 0, 0LL, ATITCDecodeFlag::ATC_RGB); + } + break; + case ATITCDecodeFlag::ATC_EXPLICIT_ALPHA: + { + memcpy((void *)&blockAlpha, encodeData, 8); + encodeData += 8; + atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, ATITCDecodeFlag::ATC_EXPLICIT_ALPHA); + } + break; + case ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA: + { + memcpy((void *)&blockAlpha, encodeData, 8); + encodeData += 8; + atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA); + } + break; + default: + break; + }//switch + }//for block_x + }//for block_y +} + + diff --git a/cocos/base/atitc/atitc.h b/cocos/base/atitc/atitc.h new file mode 100644 index 0000000000..72bfd32a8c --- /dev/null +++ b/cocos/base/atitc/atitc.h @@ -0,0 +1,48 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + + +#ifndef COCOS2DX_PLATFORM_THIRDPARTY_ATITC_ +#define COCOS2DX_PLATFORM_THIRDPARTY_ATITC_ + +#include "CCStdC.h" + +enum class ATITCDecodeFlag +{ + ATC_RGB = 1, + ATC_EXPLICIT_ALPHA = 3, + ATC_INTERPOLATED_ALPHA = 5, +}; + +//Decode ATITC encode data to RGB32 +void atitc_decode(uint8_t *encode_data, + uint8_t *decode_data, + const int pixelsWidth, + const int pixelsHeight, + ATITCDecodeFlag decodeFlag + ); + + +#endif /* defined(COCOS2DX_PLATFORM_THIRDPARTY_ATITC_) */ + diff --git a/cocos/base/cocoa/CCAffineTransform.cpp b/cocos/base/cocoa/CCAffineTransform.cpp new file mode 100644 index 0000000000..2e39f344cc --- /dev/null +++ b/cocos/base/cocoa/CCAffineTransform.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#include "CCAffineTransform.h" +#include +#include + +using namespace std; + + +NS_CC_BEGIN + +AffineTransform __CCAffineTransformMake(float a, float b, float c, float d, float tx, float ty) +{ + AffineTransform t; + t.a = a; t.b = b; t.c = c; t.d = d; t.tx = tx; t.ty = ty; + return t; +} + +Point __CCPointApplyAffineTransform(const Point& point, const AffineTransform& t) +{ + Point p; + p.x = (float)((double)t.a * point.x + (double)t.c * point.y + t.tx); + p.y = (float)((double)t.b * point.x + (double)t.d * point.y + t.ty); + return p; +} + +Size __CCSizeApplyAffineTransform(const Size& size, const AffineTransform& t) +{ + Size s; + s.width = (float)((double)t.a * size.width + (double)t.c * size.height); + s.height = (float)((double)t.b * size.width + (double)t.d * size.height); + return s; +} + + +AffineTransform AffineTransformMakeIdentity() +{ + return __CCAffineTransformMake(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); +} + +extern const AffineTransform AffineTransformIdentity = AffineTransformMakeIdentity(); +const AffineTransform AffineTransform::IDENTITY = AffineTransformMakeIdentity(); + +Rect RectApplyAffineTransform(const Rect& rect, const AffineTransform& anAffineTransform) +{ + float top = rect.getMinY(); + float left = rect.getMinX(); + float right = rect.getMaxX(); + float bottom = rect.getMaxY(); + + Point topLeft = PointApplyAffineTransform(Point(left, top), anAffineTransform); + Point topRight = PointApplyAffineTransform(Point(right, top), anAffineTransform); + Point bottomLeft = PointApplyAffineTransform(Point(left, bottom), anAffineTransform); + Point bottomRight = PointApplyAffineTransform(Point(right, bottom), anAffineTransform); + + float minX = min(min(topLeft.x, topRight.x), min(bottomLeft.x, bottomRight.x)); + float maxX = max(max(topLeft.x, topRight.x), max(bottomLeft.x, bottomRight.x)); + float minY = min(min(topLeft.y, topRight.y), min(bottomLeft.y, bottomRight.y)); + float maxY = max(max(topLeft.y, topRight.y), max(bottomLeft.y, bottomRight.y)); + + return Rect(minX, minY, (maxX - minX), (maxY - minY)); +} + +AffineTransform AffineTransformTranslate(const AffineTransform& t, float tx, float ty) +{ + return __CCAffineTransformMake(t.a, t.b, t.c, t.d, t.tx + t.a * tx + t.c * ty, t.ty + t.b * tx + t.d * ty); +} + +AffineTransform AffineTransformScale(const AffineTransform& t, float sx, float sy) +{ + return __CCAffineTransformMake(t.a * sx, t.b * sx, t.c * sy, t.d * sy, t.tx, t.ty); +} + +AffineTransform AffineTransformRotate(const AffineTransform& t, float anAngle) +{ + float sine = sinf(anAngle); + float cosine = cosf(anAngle); + + return __CCAffineTransformMake( t.a * cosine + t.c * sine, + t.b * cosine + t.d * sine, + t.c * cosine - t.a * sine, + t.d * cosine - t.b * sine, + t.tx, + t.ty); +} + +/* Concatenate `t2' to `t1' and return the result: + t' = t1 * t2 */ +AffineTransform AffineTransformConcat(const AffineTransform& t1, const AffineTransform& t2) +{ + return __CCAffineTransformMake( t1.a * t2.a + t1.b * t2.c, t1.a * t2.b + t1.b * t2.d, //a,b + t1.c * t2.a + t1.d * t2.c, t1.c * t2.b + t1.d * t2.d, //c,d + t1.tx * t2.a + t1.ty * t2.c + t2.tx, //tx + t1.tx * t2.b + t1.ty * t2.d + t2.ty); //ty +} + +/* Return true if `t1' and `t2' are equal, false otherwise. */ +bool AffineTransformEqualToTransform(const AffineTransform& t1, const AffineTransform& t2) +{ + return (t1.a == t2.a && t1.b == t2.b && t1.c == t2.c && t1.d == t2.d && t1.tx == t2.tx && t1.ty == t2.ty); +} + +AffineTransform AffineTransformInvert(const AffineTransform& t) +{ + float determinant = 1 / (t.a * t.d - t.b * t.c); + + return __CCAffineTransformMake(determinant * t.d, -determinant * t.b, -determinant * t.c, determinant * t.a, + determinant * (t.c * t.ty - t.d * t.tx), determinant * (t.b * t.tx - t.a * t.ty) ); +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCAffineTransform.h b/cocos/base/cocoa/CCAffineTransform.h new file mode 100644 index 0000000000..667b5d9b46 --- /dev/null +++ b/cocos/base/cocoa/CCAffineTransform.h @@ -0,0 +1,63 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __COCOA_CGAFFINETRANSFORM_H__ +#define __COCOA_CGAFFINETRANSFORM_H__ + +#include "CCGeometry.h" +#include "platform/CCPlatformMacros.h" + +NS_CC_BEGIN + +struct AffineTransform { + float a, b, c, d; + float tx, ty; + + static const AffineTransform IDENTITY; +}; + +CC_DLL AffineTransform __CCAffineTransformMake(float a, float b, float c, float d, float tx, float ty); +#define AffineTransformMake __CCAffineTransformMake + +CC_DLL Point __CCPointApplyAffineTransform(const Point& point, const AffineTransform& t); +#define PointApplyAffineTransform __CCPointApplyAffineTransform + +CC_DLL Size __CCSizeApplyAffineTransform(const Size& size, const AffineTransform& t); +#define SizeApplyAffineTransform __CCSizeApplyAffineTransform + +CC_DLL AffineTransform AffineTransformMakeIdentity(); +CC_DLL Rect RectApplyAffineTransform(const Rect& rect, const AffineTransform& anAffineTransform); + +CC_DLL AffineTransform AffineTransformTranslate(const AffineTransform& t, float tx, float ty); +CC_DLL AffineTransform AffineTransformRotate(const AffineTransform& aTransform, float anAngle); +CC_DLL AffineTransform AffineTransformScale(const AffineTransform& t, float sx, float sy); +CC_DLL AffineTransform AffineTransformConcat(const AffineTransform& t1, const AffineTransform& t2); +CC_DLL bool AffineTransformEqualToTransform(const AffineTransform& t1, const AffineTransform& t2); +CC_DLL AffineTransform AffineTransformInvert(const AffineTransform& t); + +extern CC_DLL const AffineTransform AffineTransformIdentity; + +NS_CC_END + +#endif // __COCOA_CGAFFINETRANSFORM_H__ diff --git a/cocos/base/cocoa/CCArray.cpp b/cocos/base/cocoa/CCArray.cpp new file mode 100644 index 0000000000..3a55d6050d --- /dev/null +++ b/cocos/base/cocoa/CCArray.cpp @@ -0,0 +1,754 @@ +/**************************************************************************** +Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#include "CCArray.h" +#include "CCString.h" +#include "platform/CCFileUtils.h" + +NS_CC_BEGIN + + +#if CC_USE_ARRAY_VECTOR + +// ---------------------------------------------------------------------------------- +// std::vector implementation +// ---------------------------------------------------------------------------------- + +Array::Array() +: data(NULL) +{ + init(); +} + +Array* Array::create() +{ + Array* array = new Array(); + + if (array && array->initWithCapacity(7)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::createWithObject(Object* object) +{ + Array* array = new Array(); + + if (array && array->initWithObject(object)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::create(Object* object, ...) +{ + va_list args; + va_start(args,object); + + Array* array = create(); + if (array && object) + { + array->addObject(object); + Object *i = va_arg(args, Object*); + while (i) + { + array->addObject(i); + i = va_arg(args, Object*); + } + } + else + { + CC_SAFE_DELETE(array); + } + + va_end(args); + + return array; +} + +Array* Array::createWithArray(Array* otherArray) +{ + return otherArray->clone(); +} + +Array* Array::createWithCapacity(int capacity) +{ + CCASSERT(capacity>=0, "Invalid capacity"); + + Array* array = new Array(); + + if (array && array->initWithCapacity(capacity)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::createWithContentsOfFile(const char* fileName) +{ + Array* ret = Array::createWithContentsOfFileThreadSafe(fileName); + if (ret != nullptr) + { + ret->autorelease(); + } + return ret; +} + +Array* Array::createWithContentsOfFileThreadSafe(const char* fileName) +{ + return FileUtils::getInstance()->createArrayWithContentsOfFile(fileName); +} + +bool Array::init() +{ + return initWithCapacity(7); +} + +bool Array::initWithObject(Object* object) +{ + bool ret = initWithCapacity(7); + if (ret) + { + addObject(object); + } + return ret; +} + +/** Initializes an array with some objects */ +bool Array::initWithObjects(Object* object, ...) +{ + bool ret = false; + do + { + CC_BREAK_IF(object == nullptr); + + va_list args; + va_start(args, object); + + if (object) + { + this->addObject(object); + Object* i = va_arg(args, Object*); + while (i) + { + this->addObject(i); + i = va_arg(args, Object*); + } + ret = true; + } + va_end(args); + + } while (false); + + return ret; +} + +bool Array::initWithCapacity(int capacity) +{ + CCASSERT(capacity>=0, "Invalid capacity"); + + data.reserve(capacity); + return true; +} + +bool Array::initWithArray(Array* otherArray) +{ + data = otherArray->data; + return true; +} + +int Array::getIndexOfObject(Object* object) const +{ + auto it = data.begin(); + + for (int i = 0; it != data.end(); ++it, ++i) + { + if (it->get() == object) + { + return i; + } + } + + return -1; +} + +Object* Array::getRandomObject() +{ + if (data.size()==0) + { + return nullptr; + } + + float r = CCRANDOM_0_1(); + + if (r == 1) // to prevent from accessing data-arr[data->num], out of range. + { + r = 0; + } + + r *= data.size(); + + return data[r].get(); +} + +bool Array::containsObject(Object* object) const +{ + int i = this->getIndexOfObject(object); + return (i >=0); +} + +bool Array::isEqualToArray(Array* otherArray) +{ + for (int i = 0; i< this->count(); i++) + { + if (!this->getObjectAtIndex(i)->isEqual(otherArray->getObjectAtIndex(i))) + { + return false; + } + } + return true; +} + +void Array::addObject(Object* object) +{ + data.push_back( RCPtr(object) ); +} + +void Array::addObjectsFromArray(Array* otherArray) +{ + data.insert(data.end(), otherArray->data.begin(), otherArray->data.end()); +} + +void Array::insertObject(Object* object, int index) +{ + data.insert( std::begin(data) + index, RCPtr(object) ); +} + +void Array::setObject(Object* object, int index) +{ + data[index] = RCPtr(object); +} + +void Array::removeLastObject(bool releaseObj) +{ + CCASSERT(data.size(), "no objects added"); + data.pop_back(); +} + +void Array::removeObject(Object* object, bool releaseObj /* ignored */) +{ + data.erase( std::remove( data.begin(), data.end(), object ) ); +} + +void Array::removeObjectAtIndex(int index, bool releaseObj /* ignored */) +{ + auto obj = data[index]; + data.erase( data.begin() + index ); +} + +void Array::removeObjectsInArray(Array* otherArray) +{ + CCASSERT(false, "not implemented"); +} + +void Array::removeAllObjects() +{ + data.erase(std::begin(data), std::end(data)); +} + +void Array::fastRemoveObjectAtIndex(int index) +{ + removeObjectAtIndex(index); +} + +void Array::fastRemoveObject(Object* object) +{ + removeObject(object); +} + +void Array::exchangeObject(Object* object1, Object* object2) +{ + int idx1 = getIndexOfObject(object1); + int idx2 = getIndexOfObject(object2); + + CCASSERT(idx1>=0 && idx2>=2, "invalid object index"); + + std::swap( data[idx1], data[idx2] ); +} + +void Array::exchangeObjectAtIndex(int index1, int index2) +{ + std::swap( data[index1], data[index2] ); +} + +void Array::replaceObjectAtIndex(int index, Object* object, bool releaseObject /* ignored */) +{ + data[index] = object; +} + +void Array::reverseObjects() +{ + std::reverse( std::begin(data), std::end(data) ); +} + +void Array::reduceMemoryFootprint() +{ + // N/A +} + +Array::~Array() +{ + CCLOGINFO("deallocing Array: %p - len: %d", this, count() ); +} + +Array* Array::clone() const +{ + Array* ret = new Array(); + ret->autorelease(); + ret->initWithCapacity(this->data.size() > 0 ? this->data.size() : 1); + + Object* obj = nullptr; + Object* tmpObj = nullptr; + Clonable* clonable = nullptr; + CCARRAY_FOREACH(this, obj) + { + clonable = dynamic_cast(obj); + if (clonable) + { + tmpObj = dynamic_cast(clonable->clone()); + if (tmpObj) + { + ret->addObject(tmpObj); + } + } + else + { + CCLOGWARN("%s isn't clonable.", typeid(*obj).name()); + } + } + return ret; +} + +void Array::acceptVisitor(DataVisitor &visitor) +{ + visitor.visit(this); +} + +// ---------------------------------------------------------------------------------- +// ccArray implementation +// ---------------------------------------------------------------------------------- + +#else + +Array::Array() +: data(nullptr) +{ +// init(); +} + +Array* Array::create() +{ + Array* array = new Array(); + + if (array && array->initWithCapacity(7)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::createWithObject(Object* object) +{ + Array* array = new Array(); + + if (array && array->initWithObject(object)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::create(Object* object, ...) +{ + va_list args; + va_start(args,object); + + Array* array = create(); + if (array && object) + { + array->addObject(object); + Object *i = va_arg(args, Object*); + while (i) + { + array->addObject(i); + i = va_arg(args, Object*); + } + } + else + { + CC_SAFE_DELETE(array); + } + + va_end(args); + + return array; +} + +Array* Array::createWithArray(Array* otherArray) +{ + return otherArray->clone(); +} + +Array* Array::createWithCapacity(int capacity) +{ + CCASSERT(capacity>=0, "Invalid capacity"); + + Array* array = new Array(); + + if (array && array->initWithCapacity(capacity)) + { + array->autorelease(); + } + else + { + CC_SAFE_DELETE(array); + } + + return array; +} + +Array* Array::createWithContentsOfFile(const char* fileName) +{ + Array* ret = Array::createWithContentsOfFileThreadSafe(fileName); + if (ret != nullptr) + { + ret->autorelease(); + } + return ret; +} + +Array* Array::createWithContentsOfFileThreadSafe(const char* fileName) +{ + return FileUtils::getInstance()->createArrayWithContentsOfFile(fileName); +} + +bool Array::init() +{ + CCASSERT(!data, "Array cannot be re-initialized"); + + return initWithCapacity(7); +} + +bool Array::initWithObject(Object* object) +{ + CCASSERT(!data, "Array cannot be re-initialized"); + + bool ret = initWithCapacity(7); + if (ret) + { + addObject(object); + } + return ret; +} + +/** Initializes an array with some objects */ +bool Array::initWithObjects(Object* object, ...) +{ + CCASSERT(!data, "Array cannot be re-initialized"); + + bool ret = false; + do + { + CC_BREAK_IF(object == nullptr); + + va_list args; + va_start(args, object); + + if (object) + { + this->addObject(object); + Object* i = va_arg(args, Object*); + while (i) + { + this->addObject(i); + i = va_arg(args, Object*); + } + ret = true; + } + va_end(args); + + } while (false); + + return ret; +} + +bool Array::initWithCapacity(int capacity) +{ + CCASSERT(capacity>=0 && !data, "Array cannot be re-initialized"); + + data = ccArrayNew(capacity); + return true; +} + +bool Array::initWithArray(Array* otherArray) +{ + CCASSERT(!data, "Array cannot be re-initialized"); + + bool ret = false; + do + { + CC_BREAK_IF(! initWithCapacity(otherArray->data->num)); + + addObjectsFromArray(otherArray); + ret = true; + } while (0); + + return ret; +} + +int Array::getIndexOfObject(Object* object) const +{ + return ccArrayGetIndexOfObject(data, object); +} + +Object* Array::getRandomObject() +{ + if (data->num == 0) + { + return nullptr; + } + + float r = CCRANDOM_0_1(); + + if (r == 1) // to prevent from accessing data-arr[data->num], out of range. + { + r = 0; + } + + return data->arr[(int)(data->num * r)]; +} + +bool Array::containsObject(Object* object) const +{ + return ccArrayContainsObject(data, object); +} + +bool Array::isEqualToArray(Array* otherArray) +{ + for (int i = 0; i< this->count(); i++) + { + if (!this->getObjectAtIndex(i)->isEqual(otherArray->getObjectAtIndex(i))) + { + return false; + } + } + return true; +} + +void Array::addObject(Object* object) +{ + CCASSERT(data, "Array not initialized"); + ccArrayAppendObjectWithResize(data, object); +} + +void Array::addObjectsFromArray(Array* otherArray) +{ + CCASSERT(data, "Array not initialized"); + ccArrayAppendArrayWithResize(data, otherArray->data); +} + +void Array::insertObject(Object* object, int index) +{ + CCASSERT(data, "Array not initialized"); + ccArrayInsertObjectAtIndex(data, object, index); +} + +void Array::setObject(Object* object, int index) +{ + CCASSERT(index>=0 && index < count(), "Invalid index"); + + if (object != data->arr[index]) + { + data->arr[index]->release(); + data->arr[index] = object; + object->retain(); + } +} + +void Array::removeLastObject(bool releaseObj) +{ + CCASSERT(data->num, "no objects added"); + ccArrayRemoveObjectAtIndex(data, data->num-1, releaseObj); +} + +void Array::removeObject(Object* object, bool releaseObj/* = true*/) +{ + ccArrayRemoveObject(data, object, releaseObj); +} + +void Array::removeObjectAtIndex(int index, bool releaseObj) +{ + ccArrayRemoveObjectAtIndex(data, index, releaseObj); +} + +void Array::removeObjectsInArray(Array* otherArray) +{ + ccArrayRemoveArray(data, otherArray->data); +} + +void Array::removeAllObjects() +{ + ccArrayRemoveAllObjects(data); +} + +void Array::fastRemoveObjectAtIndex(int index) +{ + ccArrayFastRemoveObjectAtIndex(data, index); +} + +void Array::fastRemoveObject(Object* object) +{ + ccArrayFastRemoveObject(data, object); +} + +void Array::exchangeObject(Object* object1, Object* object2) +{ + int index1 = ccArrayGetIndexOfObject(data, object1); + if (index1 == UINT_MAX) + { + return; + } + + int index2 = ccArrayGetIndexOfObject(data, object2); + if (index2 == UINT_MAX) + { + return; + } + + ccArraySwapObjectsAtIndexes(data, index1, index2); +} + +void Array::exchangeObjectAtIndex(int index1, int index2) +{ + ccArraySwapObjectsAtIndexes(data, index1, index2); +} + +void Array::replaceObjectAtIndex(int index, Object* object, bool releaseObject/* = true*/) +{ + ccArrayInsertObjectAtIndex(data, object, index); + ccArrayRemoveObjectAtIndex(data, index+1); +} + +void Array::reverseObjects() +{ + if (data->num > 1) + { + // floorf(), since in the case of an even number, the number of swaps stays the same + int count = (int) floorf(data->num/2.f); + int maxIndex = data->num - 1; + + for (int i = 0; i < count ; i++) + { + ccArraySwapObjectsAtIndexes(data, i, maxIndex); + --maxIndex; + } + } +} + +void Array::reduceMemoryFootprint() +{ + ccArrayShrink(data); +} + +Array::~Array() +{ + CCLOGINFO("deallocing Array: %p - len: %d", this, count() ); + + ccArrayFree(data); +} + +Array* Array::clone() const +{ + Array* ret = new Array(); + ret->autorelease(); + ret->initWithCapacity(this->data->num > 0 ? this->data->num : 1); + + Object* obj = nullptr; + Object* tmpObj = nullptr; + Clonable* clonable = nullptr; + CCARRAY_FOREACH(this, obj) + { + clonable = dynamic_cast(obj); + if (clonable) + { + tmpObj = dynamic_cast(clonable->clone()); + if (tmpObj) + { + ret->addObject(tmpObj); + } + } + else + { + CCLOGWARN("%s isn't clonable.", typeid(*obj).name()); + } + } + return ret; +} + +void Array::acceptVisitor(DataVisitor &visitor) +{ + visitor.visit(this); +} + +#endif // uses ccArray + +NS_CC_END diff --git a/cocos/base/cocoa/CCArray.h b/cocos/base/cocoa/CCArray.h new file mode 100644 index 0000000000..4f5beea501 --- /dev/null +++ b/cocos/base/cocoa/CCArray.h @@ -0,0 +1,557 @@ +/**************************************************************************** +Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#ifndef __CCARRAY_H__ +#define __CCARRAY_H__ + +#define CC_USE_ARRAY_VECTOR 0 + +#if CC_USE_ARRAY_VECTOR +#include +#include +#include "cocoa/CCObject.h" +#include "ccMacros.h" +#else +#include "support/data_support/ccCArray.h" +#endif + + +#if CC_USE_ARRAY_VECTOR +/** + * A reference counting-managed pointer for classes derived from RCBase which can + * be used as C pointer + * Original code: http://www.codeproject.com/Articles/64111/Building-a-Quick-and-Handy-Reference-Counting-Clas + * License: http://www.codeproject.com/info/cpol10.aspx + */ +template < class T > +class RCPtr +{ +public: + //Construct using a C pointer + //e.g. RCPtr< T > x = new T(); + RCPtr(T* ptr = nullptr) + : _ptr(ptr) + { + if(ptr != nullptr) {ptr->retain();} + } + + //Copy constructor + RCPtr(const RCPtr &ptr) + : _ptr(ptr._ptr) + { +// printf("Array: copy constructor: %p\n", this); + if(_ptr != NULL) {_ptr->retain();} + } + + //Move constructor + RCPtr(RCPtr &&ptr) + : _ptr(ptr._ptr) + { +// printf("Array: Move Constructor: %p\n", this); + ptr._ptr = nullptr; + } + + ~RCPtr() + { +// printf("Array: Destructor: %p\n", this); + if(_ptr != nullptr) {_ptr->release();} + } + + //Assign a pointer + //e.g. x = new T(); + RCPtr &operator=(T* ptr) + { +// printf("Array: operator= T*: %p\n", this); + + //The following grab and release operations have to be performed + //in that order to handle the case where ptr == _ptr + //(See comment below by David Garlisch) + if(ptr != nullptr) {ptr->retain();} + if(_ptr != nullptr) {_ptr->release();} + _ptr = ptr; + return (*this); + } + + //Assign another RCPtr + RCPtr &operator=(const RCPtr &ptr) + { +// printf("Array: operator= const&: %p\n", this); + return (*this) = ptr._ptr; + } + + //Retrieve actual pointer + T* get() const + { + return _ptr; + } + + //Some overloaded operators to facilitate dealing with an RCPtr + //as a conventional C pointer. + //Without these operators, one can still use the less transparent + //get() method to access the pointer. + T* operator->() const {return _ptr;} //x->member + T &operator*() const {return *_ptr;} //*x, (*x).member + explicit operator T*() const {return _ptr;} //T* y = x; + explicit operator bool() const {return _ptr != nullptr;} //if(x) {/*x is not NULL*/} + bool operator==(const RCPtr &ptr) {return _ptr == ptr._ptr;} + bool operator==(const T *ptr) {return _ptr == ptr;} + +private: + T *_ptr; //Actual pointer +}; +#endif // CC_USE_ARRAY_VECTOR + + +/** + * @addtogroup data_structures + * @{ + */ + +/** @def CCARRAY_FOREACH +A convenience macro to iterate over a Array using. It is faster than the "fast enumeration" interface. +@since v0.99.4 +*/ + +/* +In cocos2d-iphone 1.0.0, This macro have been update to like this: + +#define CCARRAY_FOREACH(__array__, __object__) \ +if (__array__ && __array__->data->num > 0) \ +for(id *__arr__ = __array__->data->arr, *end = __array__->data->arr + __array__->data->num-1; \ +__arr__ <= end && ((__object__ = *__arr__) != nil || true); \ +__arr__++) + +I found that it's not work in C++. So it keep what it's look like in version 1.0.0-rc3. ---By Bin +*/ + +#if CC_USE_ARRAY_VECTOR +#define CCARRAY_FOREACH(__array__, __object__) \ + if (__array__) \ + for( auto __it__ = (__array__)->data.begin(); \ + __it__ != (__array__)->data.end() && ((__object__) = __it__->get()) != nullptr; \ + ++__it__) + + +#define CCARRAY_FOREACH_REVERSE(__array__, __object__) \ + if (__array__) \ + for( auto __it__ = (__array__)->data.rbegin(); \ + __it__ != (__array__)->data.rend() && ((__object__) = __it__->get()) != nullptr; \ + ++__it__ ) + + +#define CCARRAY_VERIFY_TYPE(__array__, __type__) void(0) + +#else // ! CC_USE_ARRAY_VECTOR -------------------------- + +#define CCARRAY_FOREACH(__array__, __object__) \ + if ((__array__) && (__array__)->data->num > 0) \ + for(Object** __arr__ = (__array__)->data->arr, **__end__ = (__array__)->data->arr + (__array__)->data->num-1; \ + __arr__ <= __end__ && (((__object__) = *__arr__) != NULL/* || true*/); \ + __arr__++) + +#define CCARRAY_FOREACH_REVERSE(__array__, __object__) \ + if ((__array__) && (__array__)->data->num > 0) \ + for(Object** __arr__ = (__array__)->data->arr + (__array__)->data->num-1, **__end__ = (__array__)->data->arr; \ + __arr__ >= __end__ && (((__object__) = *__arr__) != NULL/* || true*/); \ + __arr__--) + +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) +#define CCARRAY_VERIFY_TYPE(__array__, __type__) \ + do { \ + if ((__array__) && (__array__)->data->num > 0) \ + for(Object** __arr__ = (__array__)->data->arr, \ + **__end__ = (__array__)->data->arr + (__array__)->data->num-1; __arr__ <= __end__; __arr__++) \ + CCASSERT(dynamic_cast<__type__>(*__arr__), "element type is wrong!"); \ + } while(false) +#else +#define CCARRAY_VERIFY_TYPE(__array__, __type__) void(0) +#endif + +#endif // ! CC_USE_ARRAY_VECTOR + + +// Common defines ----------------------------------------------------------------------------------------------- + +#define arrayMakeObjectsPerformSelector(pArray, func, elementType) \ +do { \ + if(pArray && pArray->count() > 0) \ + { \ + Object* child; \ + CCARRAY_FOREACH(pArray, child) \ + { \ + elementType pNode = static_cast(child); \ + if(pNode) \ + { \ + pNode->func(); \ + } \ + } \ + } \ +} \ +while(false) + +#define arrayMakeObjectsPerformSelectorWithObject(pArray, func, object, elementType) \ +do { \ + if(pArray && pArray->count() > 0) \ + { \ + Object* child; \ + CCARRAY_FOREACH(pArray, child) \ + { \ + elementType pNode = static_cast(child); \ + if(pNode) \ + { \ + pNode->func(object); \ + } \ + } \ + } \ +} \ +while(false) + + +NS_CC_BEGIN + +class CC_DLL Array : public Object, public Clonable +{ +public: + + /** Creates an empty array. Default capacity is 10 + * @js NA + * @lua NA + */ + static Array* create(); + /** Create an array with objects + * @js NA + */ + static Array* create(Object* object, ...) CC_REQUIRES_NULL_TERMINATION; + /** Create an array with one object + * @js NA + */ + static Array* createWithObject(Object* object); + /** Create an array with a default capacity + * @js NA + */ + static Array* createWithCapacity(int capacity); + /** Create an array with from an existing array + * @js NA + */ + static Array* createWithArray(Array* otherArray); + /** + @brief Generate a Array pointer by file + @param pFileName The file name of *.plist file + @return The Array pointer generated from the file + * @js NA + */ + static Array* createWithContentsOfFile(const char* pFileName); + + /* + @brief The same meaning as arrayWithContentsOfFile(), but it doesn't call autorelease, so the + invoker should call release(). + * @js NA + * @lua NA + */ + static Array* createWithContentsOfFileThreadSafe(const char* pFileName); + /** + * @js NA + * @lua NA + */ + ~Array(); + + /** Initializes an array + * @js NA + * @lua NA + */ + bool init(); + /** Initializes an array with one object + * @js NA + * @lua NA + */ + bool initWithObject(Object* object); + /** Initializes an array with some objects + * @js NA + * @lua NA + */ + bool initWithObjects(Object* object, ...) CC_REQUIRES_NULL_TERMINATION; + /** Initializes an array with capacity + * @js NA + * @lua NA + */ + bool initWithCapacity(int capacity); + /** Initializes an array with an existing array + * @js NA + * @lua NA + */ + bool initWithArray(Array* otherArray); + + // Querying an Array + + /** Returns element count of the array + * @js NA + */ + int count() const + { +#if CC_USE_ARRAY_VECTOR + return data.size(); +#else + return data->num; +#endif + } + /** Returns capacity of the array + * @js NA + */ + int capacity() const + { +#if CC_USE_ARRAY_VECTOR + return data.capacity(); +#else + return data->max; +#endif + } + /** Returns index of a certain object, return UINT_MAX if doesn't contain the object + * @js NA + * @lua NA + */ + int getIndexOfObject(Object* object) const; + /** + * @js NA + */ + CC_DEPRECATED_ATTRIBUTE int indexOfObject(Object* object) const { return getIndexOfObject(object); } + + /** Returns an element with a certain index + * @js NA + * @lua NA + */ + Object* getObjectAtIndex(int index) + { + CCASSERT(index>=0 && index < count(), "index out of range in getObjectAtIndex()"); +#if CC_USE_ARRAY_VECTOR + return data[index].get(); +#else + return data->arr[index]; +#endif + } + CC_DEPRECATED_ATTRIBUTE Object* objectAtIndex(int index) { return getObjectAtIndex(index); } + /** Returns the last element of the array + * @js NA + */ + Object* getLastObject() + { +#if CC_USE_ARRAY_VECTOR + return data.back().get(); +#else + if(data->num > 0) + return data->arr[data->num-1]; + + return nullptr; +#endif + } + /** + * @js NA + */ + CC_DEPRECATED_ATTRIBUTE Object* lastObject() { return getLastObject(); } + /** Returns a random element + * @js NA + * @lua NA + */ + Object* getRandomObject(); + /** + * @js NA + */ + CC_DEPRECATED_ATTRIBUTE Object* randomObject() { return getRandomObject(); } + /** Returns a Boolean value that indicates whether object is present in array. + * @js NA + */ + bool containsObject(Object* object) const; + /** @since 1.1 + * @js NA + */ + bool isEqualToArray(Array* otherArray); + // Adding Objects + + /** Add a certain object + * @js NA + */ + void addObject(Object* object); + /** + * @js NA + */ + /** Add all elements of an existing array + * @js NA + */ + void addObjectsFromArray(Array* otherArray); + /** Insert a certain object at a certain index + * @js NA + */ + void insertObject(Object* object, int index); + /** sets a certain object at a certain index + * @js NA + * @lua NA + */ + void setObject(Object* object, int index); + /** sets a certain object at a certain index without retaining. Use it with caution + * @js NA + * @lua NA + */ + void fastSetObject(Object* object, int index) + { +#if CC_USE_ARRAY_VECTOR + setObject(object, index); +#else + // no retain + data->arr[index] = object; +#endif + } + /** + * @js NA + * @lua NA + */ + void swap( int indexOne, int indexTwo ) + { + CCASSERT(indexOne >=0 && indexOne < count() && indexTwo >= 0 && indexTwo < count(), "Invalid indices"); +#if CC_USE_ARRAY_VECTOR + std::swap(data[indexOne], data[indexTwo]); +#else + std::swap(data->arr[indexOne], data->arr[indexTwo]); +#endif + } + + // Removing Objects + + /** Remove last object + * @js NA + */ + void removeLastObject(bool releaseObj = true); + /** Remove a certain object + * @js NA + */ + void removeObject(Object* object, bool releaseObj = true); + /** Remove an element with a certain index + * @js NA + */ + void removeObjectAtIndex(int index, bool releaseObj = true); + /** Remove all elements + * @js NA + */ + void removeObjectsInArray(Array* otherArray); + /** Remove all objects + * @js NA + */ + void removeAllObjects(); + /** Fast way to remove a certain object + * @js NA + */ + void fastRemoveObject(Object* object); + /** Fast way to remove an element with a certain index + * @js NA + */ + void fastRemoveObjectAtIndex(int index); + + // Rearranging Content + + /** Swap two elements + * @js NA + */ + void exchangeObject(Object* object1, Object* object2); + /** Swap two elements with certain indexes + * @js NA + */ + void exchangeObjectAtIndex(int index1, int index2); + + /** Replace object at index with another object. + * @js NA + */ + void replaceObjectAtIndex(int index, Object* object, bool releaseObject = true); + + /** Revers the array + * @js NA + */ + void reverseObjects(); + /* Shrinks the array so the memory footprint corresponds with the number of items + * @js NA + */ + void reduceMemoryFootprint(); + + /* override functions + * @js NA + */ + virtual void acceptVisitor(DataVisitor &visitor); + /** + * @js NA + * @lua NA + */ + virtual Array* clone() const; + + // ------------------------------------------ + // Iterators + // ------------------------------------------ +#if CC_USE_ARRAY_VECTOR + typedef std::vector>::iterator iterator; + typedef std::vector>::const_iterator const_iterator; + /** + * @js NA + * @lua NA + */ + iterator begin() { return data.begin(); } + /** + * @js NA + * @lua NA + */ + iterator end() { return data.end(); } + const_iterator cbegin() { return data.cbegin(); } + /** + * @js NA + * @lua NA + */ + const_iterator cend() { return data.cend(); } + + std::vector> data; + +#else + /** + * @js NA + * @lua NA + */ + Object** begin() { return &data->arr[0]; } + /** + * @js NA + * @lua NA + */ + Object** end() { return &data->arr[data->num]; } + + ccArray* data; + +#endif + +//protected: + /** + * @js NA + * @lua NA + */ + Array(); +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif // __CCARRAY_H__ diff --git a/cocos/base/cocoa/CCAutoreleasePool.cpp b/cocos/base/cocoa/CCAutoreleasePool.cpp new file mode 100644 index 0000000000..89a3528f73 --- /dev/null +++ b/cocos/base/cocoa/CCAutoreleasePool.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#include "CCAutoreleasePool.h" +#include "ccMacros.h" + +NS_CC_BEGIN + +static PoolManager* s_pPoolManager = NULL; + +AutoreleasePool::AutoreleasePool() +{ + _managedObjectArray = new Array(); + _managedObjectArray->initWithCapacity(150); +} + +AutoreleasePool::~AutoreleasePool() +{ + CCLOGINFO("deallocing AutoreleasePool: %p", this); + CC_SAFE_DELETE(_managedObjectArray); +} + +void AutoreleasePool::addObject(Object* object) +{ + _managedObjectArray->addObject(object); + + CCASSERT(object->_reference > 1, "reference count should be greater than 1"); + ++(object->_autoReleaseCount); + object->release(); // no ref count, in this case autorelease pool added. +} + +void AutoreleasePool::removeObject(Object* object) +{ + for (unsigned int i = 0; i < object->_autoReleaseCount; ++i) + { + _managedObjectArray->removeObject(object, false); + } +} + +void AutoreleasePool::clear() +{ + if(_managedObjectArray->count() > 0) + { + //CCAutoreleasePool* pReleasePool; +#ifdef _DEBUG + int nIndex = _managedObjectArray->count() - 1; +#endif + + Object* pObj = NULL; + CCARRAY_FOREACH_REVERSE(_managedObjectArray, pObj) + { + if(!pObj) + break; + + --(pObj->_autoReleaseCount); + //(*it)->release(); + //delete (*it); +#ifdef _DEBUG + nIndex--; +#endif + } + + _managedObjectArray->removeAllObjects(); + } +} + + +//-------------------------------------------------------------------- +// +// PoolManager +// +//-------------------------------------------------------------------- + +PoolManager* PoolManager::sharedPoolManager() +{ + if (s_pPoolManager == NULL) + { + s_pPoolManager = new PoolManager(); + } + return s_pPoolManager; +} + +void PoolManager::purgePoolManager() +{ + CC_SAFE_DELETE(s_pPoolManager); +} + +PoolManager::PoolManager() +{ + _releasePoolStack = new Array(); + _releasePoolStack->initWithCapacity(150); + _curReleasePool = 0; +} + +PoolManager::~PoolManager() +{ + CCLOGINFO("deallocing PoolManager: %p", this); + finalize(); + + // we only release the last autorelease pool here + _curReleasePool = 0; + _releasePoolStack->removeObjectAtIndex(0); + + CC_SAFE_DELETE(_releasePoolStack); +} + +void PoolManager::finalize() +{ + if(_releasePoolStack->count() > 0) + { + //CCAutoreleasePool* pReleasePool; + Object* pObj = NULL; + CCARRAY_FOREACH(_releasePoolStack, pObj) + { + if(!pObj) + break; + AutoreleasePool* pPool = static_cast(pObj); + pPool->clear(); + } + } +} + +void PoolManager::push() +{ + AutoreleasePool* pPool = new AutoreleasePool(); //ref = 1 + _curReleasePool = pPool; + + _releasePoolStack->addObject(pPool); //ref = 2 + + pPool->release(); //ref = 1 +} + +void PoolManager::pop() +{ + if (! _curReleasePool) + { + return; + } + + int nCount = _releasePoolStack->count(); + + _curReleasePool->clear(); + + if (nCount > 1) + { + _releasePoolStack->removeObjectAtIndex(nCount-1); + +// if(nCount > 1) +// { +// _curReleasePool = _releasePoolStack->getObjectAtIndex(nCount - 2); +// return; +// } + _curReleasePool = (AutoreleasePool*)_releasePoolStack->getObjectAtIndex(nCount - 2); + } + + /*_curReleasePool = NULL;*/ +} + +void PoolManager::removeObject(Object* object) +{ + CCASSERT(_curReleasePool, "current auto release pool should not be null"); + + _curReleasePool->removeObject(object); +} + +void PoolManager::addObject(Object* object) +{ + getCurReleasePool()->addObject(object); +} + + +AutoreleasePool* PoolManager::getCurReleasePool() +{ + if(!_curReleasePool) + { + push(); + } + + CCASSERT(_curReleasePool, "current auto release pool should not be null"); + + return _curReleasePool; +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCAutoreleasePool.h b/cocos/base/cocoa/CCAutoreleasePool.h new file mode 100644 index 0000000000..e446ceb402 --- /dev/null +++ b/cocos/base/cocoa/CCAutoreleasePool.h @@ -0,0 +1,181 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#ifndef __AUTORELEASEPOOL_H__ +#define __AUTORELEASEPOOL_H__ + +#include "CCObject.h" +#include "CCArray.h" + +NS_CC_BEGIN + +/** + * @addtogroup base_nodes + * @{ + */ + +class CC_DLL AutoreleasePool : public Object +{ + /** + * The underlying array of object managed by the pool. + * + * Although Array retains the object once when an object is added, proper + * Object::release() is called outside the array to make sure that the pool + * does not affect the managed object's reference count. So an object can + * be destructed properly by calling Object::release() even if the object + * is in the pool. + */ + Array *_managedObjectArray; +public: + /** + * @js NA + * @lua NA + */ + AutoreleasePool(); + /** + * @js NA + * @lua NA + */ + ~AutoreleasePool(); + + /** + * Add a given object to this pool. + * + * The same object may be added several times to the same pool; When the + * pool is destructed, the object's Object::release() method will be called + * for each time it was added. + * + * @param object The object to add to the pool. + * @js NA + * @lua NA + */ + void addObject(Object *object); + + /** + * Remove a given object from this pool. + * + * @param object The object to be removed from the pool. + * @js NA + * @lua NA + */ + void removeObject(Object *object); + + /** + * Clear the autorelease pool. + * + * Object::release() will be called for each time the managed object is + * added to the pool. + * @js NA + * @lua NA + */ + void clear(); +}; + +class CC_DLL PoolManager +{ + Array *_releasePoolStack; + AutoreleasePool *_curReleasePool; + + AutoreleasePool *getCurReleasePool(); +public: + /** + * @js NA + * @lua NA + */ + static PoolManager* sharedPoolManager(); + /** + * @js NA + * @lua NA + */ + static void purgePoolManager(); + /** + * @js NA + * @lua NA + */ + PoolManager(); + /** + * @js NA + * @lua NA + */ + ~PoolManager(); + + /** + * Clear all the AutoreleasePool on the pool stack. + * @js NA + * @lua NA + */ + void finalize(); + + /** + * Push a new AutoreleasePool to the pool stack. + * @js NA + * @lua NA + */ + void push(); + + /** + * Pop one AutoreleasePool from the pool stack. + * + * This method will ensure that there is at least one AutoreleasePool on + * the stack. + * + * The AutoreleasePool being poped is destructed. + * @js NA + * @lua NA + */ + void pop(); + + /** + * Remove a given object from the current autorelease pool. + * + * @param object The object to be removed. + * + * @see AutoreleasePool::removeObject + * @js NA + * @lua NA + */ + void removeObject(Object *object); + + /** + * Add a given object to the current autorelease pool. + * + * @param object The object to add. + * + * @see AutoreleasePool::addObject + * @js NA + * @lua NA + */ + void addObject(Object *object); + /** + * @js NA + * @lua NA + */ + friend class AutoreleasePool; +}; + +// end of base_nodes group +/// @} + +NS_CC_END + +#endif //__AUTORELEASEPOOL_H__ diff --git a/cocos/base/cocoa/CCBool.h b/cocos/base/cocoa/CCBool.h new file mode 100644 index 0000000000..32b7b276ee --- /dev/null +++ b/cocos/base/cocoa/CCBool.h @@ -0,0 +1,70 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCBOOL_H__ +#define __CCBOOL_H__ + +#include "CCObject.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +class CC_DLL Bool : public Object, public Clonable +{ +public: + Bool(bool v) + : _value(v) {} + bool getValue() const {return _value;} + + static Bool* create(bool v) + { + Bool* pRet = new Bool(v); + if (pRet) + { + pRet->autorelease(); + } + return pRet; + } + + /* override functions */ + virtual void acceptVisitor(DataVisitor &visitor) { visitor.visit(this); } + + Bool* clone() const + { + return Bool::create(_value); + } +private: + bool _value; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif /* __CCBOOL_H__ */ diff --git a/cocos/base/cocoa/CCData.cpp b/cocos/base/cocoa/CCData.cpp new file mode 100644 index 0000000000..1c42a12ee5 --- /dev/null +++ b/cocos/base/cocoa/CCData.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include +#include "CCData.h" +#include "platform/CCCommon.h" + +NS_CC_BEGIN + +Data::Data(unsigned char *pBytes, const unsigned long nSize) +{ + _size = nSize; + _bytes = new unsigned char[_size]; + memcpy(_bytes, pBytes, _size); +} + +Data::Data(Data *pData) +{ + _size = pData->_size; + _bytes = new unsigned char[_size]; + memcpy(_bytes, pData->_bytes, _size); +} + +Data::~Data() +{ + CCLOGINFO("deallocing Data: %p", this); + CC_SAFE_DELETE_ARRAY(_bytes); +} + +unsigned char* Data::getBytes() const +{ + return _bytes; +} + +unsigned long Data::getSize() const +{ + return _size; +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCData.h b/cocos/base/cocoa/CCData.h new file mode 100644 index 0000000000..889a2d557b --- /dev/null +++ b/cocos/base/cocoa/CCData.h @@ -0,0 +1,88 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCDATA_H__ +#define __CCDATA_H__ + +#include "platform/CCPlatformMacros.h" +#include "CCObject.h" + +NS_CC_BEGIN + +class CC_DLL Data : public Object +{ +public: + /** + * @js NA + * @lua NA + */ + Data(unsigned char *pBytes, const unsigned long nSize); + /** + * @js NA + * @lua NA + */ + Data(Data *pData); + /** + * @js NA + * @lua NA + */ + ~Data(); + /** + * @js NA + * @lua NA + */ + static Data* create(unsigned char *pBytes, const unsigned long nSize) + { + Data* pRet = new Data(pBytes, nSize); + if (pRet) + { + pRet->autorelease(); + } + return pRet; + } + /** + * @js NA + * @lua NA + */ + unsigned char* getBytes() const; + /** + * @js NA + * @lua NA + */ + unsigned long getSize() const; + + /** override functions + * @js NA + * @lua NA + */ + virtual void acceptVisitor(DataVisitor &visitor) { visitor.visit(this); } + +private: + unsigned char* _bytes; + unsigned long _size; +}; + +NS_CC_END + +#endif // __CCDATA_H__ diff --git a/cocos/base/cocoa/CCDataVisitor.cpp b/cocos/base/cocoa/CCDataVisitor.cpp new file mode 100644 index 0000000000..2d2a1f8121 --- /dev/null +++ b/cocos/base/cocoa/CCDataVisitor.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCObject.h" +#include "CCBool.h" +#include "CCInteger.h" +#include "CCFloat.h" +#include "CCDouble.h" +#include "CCString.h" +#include "CCArray.h" +#include "CCDictionary.h" +#include "CCSet.h" +#include "CCData.h" + +NS_CC_BEGIN + +void DataVisitor::visit(const Bool *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Integer *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Float *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Double *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const String *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Array *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Dictionary *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Set *value) +{ + visitObject(value); +} + +void DataVisitor::visit(const Data *value) +{ + visitObject(value); +} + +// PrettyPrinter +PrettyPrinter::PrettyPrinter(int indentLevel/* = 0 */) +{ + setIndentLevel(indentLevel); +} + +void PrettyPrinter::clear() +{ + _result.clear(); +} + +std::string PrettyPrinter::getResult() +{ + return _result; +} + +void PrettyPrinter::visitObject(const Object *p) +{ + char buf[50] = {0}; + sprintf(buf, "%p", p); + _result += buf; +} + +void PrettyPrinter::visit(const Bool * p) +{ + char buf[50] = {0}; + sprintf(buf, "%s", p->getValue() ? "true" : "false"); + _result += buf; +} + +void PrettyPrinter::visit(const Integer *p) +{ + char buf[50] = {0}; + sprintf(buf, "%d", p->getValue()); + _result += buf; +} + +void PrettyPrinter::visit(const Float *p) +{ + char buf[50] = {0}; + sprintf(buf, "%f", p->getValue()); + _result += buf; +} + +void PrettyPrinter::visit(const Double *p) +{ + char buf[50] = {0}; + sprintf(buf, "%lf", p->getValue()); + _result += buf; +} + +void PrettyPrinter::visit(const String *p) +{ + _result += p->getCString(); +} + +void PrettyPrinter::visit(const Array *p) +{ + _result += "\n"; + _result += _indentStr; + _result += "\n"; + + setIndentLevel(_indentLevel+1); + Object* obj; + int i = 0; + char buf[50] = {0}; + CCARRAY_FOREACH(p, obj) + { + if (i > 0) { + _result += "\n"; + } + sprintf(buf, "%s%02d: ", _indentStr.c_str(), i); + _result += buf; + PrettyPrinter v(_indentLevel); + obj->acceptVisitor(v); + _result += v.getResult(); + i++; + } + setIndentLevel(_indentLevel-1); + + _result += "\n"; + _result += _indentStr; + _result += ""; +} + +void PrettyPrinter::visit(const Dictionary *p) +{ + _result += "\n"; + _result += _indentStr; + _result += "\n"; + + setIndentLevel(_indentLevel+1); + DictElement* element; + bool bFirstElement = true; + char buf[1000] = {0}; + CCDICT_FOREACH(p, element) + { + if (!bFirstElement) { + _result += "\n"; + } + sprintf(buf, "%s%s: ", _indentStr.c_str(),element->getStrKey()); + _result += buf; + PrettyPrinter v(_indentLevel); + element->getObject()->acceptVisitor(v); + _result += v.getResult(); + bFirstElement = false; + } + setIndentLevel(_indentLevel-1); + + _result += "\n"; + _result += _indentStr; + _result += ""; +} + +void PrettyPrinter::visit(const Set *p) +{ + _result += "\n"; + _result += _indentStr; + _result += "\n"; + + setIndentLevel(_indentLevel+1); + + int i = 0; + Set* tmp = const_cast(p); + SetIterator it = tmp->begin(); + + for (; it != tmp->end(); ++it, ++i) { + if (i > 0) { + _result += "\n"; + } + _result += _indentStr.c_str(); + PrettyPrinter v(_indentLevel); + (*it)->acceptVisitor(v); + _result += v.getResult(); + } + setIndentLevel(_indentLevel-1); + + _result += "\n"; + _result += _indentStr; + _result += "\n"; +} + +void PrettyPrinter::visit(const Data *p) +{ + //TODO Implement + DataVisitor::visit(p); +} + +void PrettyPrinter::setIndentLevel(int indentLevel) +{ + _indentLevel = indentLevel; + _indentStr.clear(); + for (int i = 0; i < _indentLevel; ++i) { + _indentStr += "\t"; + } +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCDataVisitor.h b/cocos/base/cocoa/CCDataVisitor.h new file mode 100644 index 0000000000..3395b43dea --- /dev/null +++ b/cocos/base/cocoa/CCDataVisitor.h @@ -0,0 +1,117 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCDATAVISITOR_H__ +#define __CCDATAVISITOR_H__ + +#include "platform/CCPlatformMacros.h" +#include + +NS_CC_BEGIN + +class Object; +class Bool; +class Integer; +class Float; +class Double; +class String; +class Array; +class Dictionary; +class Set; +class Data; + +/** + * @addtogroup data_structures + * @{ + */ + +/** + * Visitor that helps to perform action that depends on polymorphic object type + * + * Use cases: + * - data serialization, + * - pretty printing of Object * + * - safe value reading from Array, Dictionary, Set + * + * Usage: + * 1. subclass DataVisitor + * 2. overload visit() methods for object that you need to handle + * 3. handle other objects in visitObject() + * 4. pass your visitor to Object::acceptVisitor() + */ +class CC_DLL DataVisitor +{ +public: + /** + * @js NA + * @lua NA + */ + virtual ~DataVisitor() {} + + /** default method, called from non-overloaded methods and for unrecognized objects */ + virtual void visitObject(const Object *p) = 0; + + virtual void visit(const Bool *p); + virtual void visit(const Integer *p); + virtual void visit(const Float *p); + virtual void visit(const Double *p); + virtual void visit(const String *p); + virtual void visit(const Array *p); + virtual void visit(const Dictionary *p); + virtual void visit(const Set *p); + virtual void visit(const Data *p); +}; + + +class CC_DLL PrettyPrinter : public DataVisitor +{ +public: + PrettyPrinter(int indentLevel = 0); + + virtual void clear(); + virtual std::string getResult(); + + virtual void visitObject(const Object *p); + virtual void visit(const Bool * p); + virtual void visit(const Integer *p); + virtual void visit(const Float *p); + virtual void visit(const Double *p); + virtual void visit(const String *p); + virtual void visit(const Array *p); + virtual void visit(const Dictionary *p); + virtual void visit(const Set *p); + virtual void visit(const Data *p); +private: + void setIndentLevel(int indentLevel); + int _indentLevel; + std::string _indentStr; + std::string _result; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif // __CCDATAVISITOR_H__ diff --git a/cocos/base/cocoa/CCDictionary.cpp b/cocos/base/cocoa/CCDictionary.cpp new file mode 100644 index 0000000000..6b8df0febf --- /dev/null +++ b/cocos/base/cocoa/CCDictionary.cpp @@ -0,0 +1,454 @@ +/**************************************************************************** + Copyright (c) 2012 - 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCDictionary.h" +#include "CCString.h" +#include "CCInteger.h" +#include "platform/CCFileUtils.h" + +using namespace std; + +NS_CC_BEGIN + +// ----------------------------------------------------------------------- +// DictElement + +DictElement::DictElement(const char* pszKey, Object* pObject) +{ + CCASSERT(pszKey && strlen(pszKey) > 0, "Invalid key value."); + _intKey = 0; + const char* pStart = pszKey; + + size_t len = strlen(pszKey); + if (len > MAX_KEY_LEN ) + { + char* pEnd = (char*)&pszKey[len-1]; + pStart = pEnd - (MAX_KEY_LEN-1); + } + + strcpy(_strKey, pStart); + + _object = pObject; + memset(&hh, 0, sizeof(hh)); +} + +DictElement::DictElement(intptr_t iKey, Object* pObject) +{ + _strKey[0] = '\0'; + _intKey = iKey; + _object = pObject; + memset(&hh, 0, sizeof(hh)); +} + +DictElement::~DictElement() +{ + CCLOGINFO("deallocing DictElement: %p", this); +} + +// ----------------------------------------------------------------------- +// Dictionary + +Dictionary::Dictionary() +: _elements(NULL) +, _dictType(kDictUnknown) +{ + +} + +Dictionary::~Dictionary() +{ + CCLOGINFO("deallocing Dictionary: %p", this); + removeAllObjects(); +} + +unsigned int Dictionary::count() +{ + return HASH_COUNT(_elements); +} + +Array* Dictionary::allKeys() +{ + int iKeyCount = this->count(); + if (iKeyCount <= 0) return NULL; + + Array* pArray = Array::createWithCapacity(iKeyCount); + + DictElement *pElement, *tmp; + if (_dictType == kDictStr) + { + HASH_ITER(hh, _elements, pElement, tmp) + { + String* pOneKey = new String(pElement->_strKey); + pArray->addObject(pOneKey); + CC_SAFE_RELEASE(pOneKey); + } + } + else if (_dictType == kDictInt) + { + HASH_ITER(hh, _elements, pElement, tmp) + { + Integer* pOneKey = new Integer(pElement->_intKey); + pArray->addObject(pOneKey); + CC_SAFE_RELEASE(pOneKey); + } + } + + return pArray; +} + +Array* Dictionary::allKeysForObject(Object* object) +{ + int iKeyCount = this->count(); + if (iKeyCount <= 0) return NULL; + Array* pArray = Array::create(); + + DictElement *pElement, *tmp; + + if (_dictType == kDictStr) + { + HASH_ITER(hh, _elements, pElement, tmp) + { + if (object == pElement->_object) + { + String* pOneKey = new String(pElement->_strKey); + pArray->addObject(pOneKey); + CC_SAFE_RELEASE(pOneKey); + } + } + } + else if (_dictType == kDictInt) + { + HASH_ITER(hh, _elements, pElement, tmp) + { + if (object == pElement->_object) + { + Integer* pOneKey = new Integer(pElement->_intKey); + pArray->addObject(pOneKey); + CC_SAFE_RELEASE(pOneKey); + } + } + } + return pArray; +} + +Object* Dictionary::objectForKey(const std::string& key) +{ + // if dictionary wasn't initialized, return NULL directly. + if (_dictType == kDictUnknown) return NULL; + // Dictionary only supports one kind of key, string or integer. + // This method uses string as key, therefore we should make sure that the key type of this Dictionary is string. + CCASSERT(_dictType == kDictStr, "this dictionary does not use string as key."); + + Object* pRetObject = NULL; + DictElement *pElement = NULL; + HASH_FIND_STR(_elements, key.c_str(), pElement); + if (pElement != NULL) + { + pRetObject = pElement->_object; + } + return pRetObject; +} + +Object* Dictionary::objectForKey(intptr_t key) +{ + // if dictionary wasn't initialized, return NULL directly. + if (_dictType == kDictUnknown) return NULL; + // Dictionary only supports one kind of key, string or integer. + // This method uses integer as key, therefore we should make sure that the key type of this Dictionary is integer. + CCASSERT(_dictType == kDictInt, "this dictionary does not use integer as key."); + + Object* pRetObject = NULL; + DictElement *pElement = NULL; + HASH_FIND_PTR(_elements, &key, pElement); + if (pElement != NULL) + { + pRetObject = pElement->_object; + } + return pRetObject; +} + +const String* Dictionary::valueForKey(const std::string& key) +{ + String* pStr = dynamic_cast(objectForKey(key)); + if (pStr == NULL) + { + pStr = String::create(""); + } + return pStr; +} + +const String* Dictionary::valueForKey(intptr_t key) +{ + String* pStr = dynamic_cast(objectForKey(key)); + if (pStr == NULL) + { + pStr = String::create(""); + } + return pStr; +} + +void Dictionary::setObject(Object* pObject, const std::string& key) +{ + CCASSERT(key.length() > 0 && pObject != NULL, "Invalid Argument!"); + if (_dictType == kDictUnknown) + { + _dictType = kDictStr; + } + + CCASSERT(_dictType == kDictStr, "this dictionary doesn't use string as key."); + + DictElement *pElement = NULL; + HASH_FIND_STR(_elements, key.c_str(), pElement); + if (pElement == NULL) + { + setObjectUnSafe(pObject, key); + } + else if (pElement->_object != pObject) + { + Object* pTmpObj = pElement->_object; + pTmpObj->retain(); + removeObjectForElememt(pElement); + setObjectUnSafe(pObject, key); + pTmpObj->release(); + } +} + +void Dictionary::setObject(Object* pObject, intptr_t key) +{ + CCASSERT(pObject != NULL, "Invalid Argument!"); + if (_dictType == kDictUnknown) + { + _dictType = kDictInt; + } + + CCASSERT(_dictType == kDictInt, "this dictionary doesn't use integer as key."); + + DictElement *pElement = NULL; + HASH_FIND_PTR(_elements, &key, pElement); + if (pElement == NULL) + { + setObjectUnSafe(pObject, key); + } + else if (pElement->_object != pObject) + { + Object* pTmpObj = pElement->_object; + pTmpObj->retain(); + removeObjectForElememt(pElement); + setObjectUnSafe(pObject, key); + pTmpObj->release(); + } + +} + +void Dictionary::removeObjectForKey(const std::string& key) +{ + if (_dictType == kDictUnknown) + { + return; + } + + CCASSERT(_dictType == kDictStr, "this dictionary doesn't use string as its key"); + CCASSERT(key.length() > 0, "Invalid Argument!"); + DictElement *pElement = NULL; + HASH_FIND_STR(_elements, key.c_str(), pElement); + removeObjectForElememt(pElement); +} + +void Dictionary::removeObjectForKey(intptr_t key) +{ + if (_dictType == kDictUnknown) + { + return; + } + + CCASSERT(_dictType == kDictInt, "this dictionary doesn't use integer as its key"); + DictElement *pElement = NULL; + HASH_FIND_PTR(_elements, &key, pElement); + removeObjectForElememt(pElement); +} + +void Dictionary::setObjectUnSafe(Object* pObject, const std::string& key) +{ + pObject->retain(); + DictElement* pElement = new DictElement(key.c_str(), pObject); + HASH_ADD_STR(_elements, _strKey, pElement); +} + +void Dictionary::setObjectUnSafe(Object* pObject, const intptr_t key) +{ + pObject->retain(); + DictElement* pElement = new DictElement(key, pObject); + HASH_ADD_PTR(_elements, _intKey, pElement); +} + +void Dictionary::removeObjectsForKeys(Array* pKeyArray) +{ + Object* pObj = NULL; + CCARRAY_FOREACH(pKeyArray, pObj) + { + String* pStr = static_cast(pObj); + removeObjectForKey(pStr->getCString()); + } +} + +void Dictionary::removeObjectForElememt(DictElement* pElement) +{ + if (pElement != NULL) + { + HASH_DEL(_elements, pElement); + pElement->_object->release(); + CC_SAFE_DELETE(pElement); + } +} + +void Dictionary::removeAllObjects() +{ + DictElement *pElement, *tmp; + HASH_ITER(hh, _elements, pElement, tmp) + { + HASH_DEL(_elements, pElement); + pElement->_object->release(); + CC_SAFE_DELETE(pElement); + + } +} + +Object* Dictionary::randomObject() +{ + if (_dictType == kDictUnknown) + { + return NULL; + } + + Object* key = allKeys()->getRandomObject(); + + if (_dictType == kDictInt) + { + return objectForKey( static_cast(key)->getValue()); + } + else if (_dictType == kDictStr) + { + return objectForKey( static_cast(key)->getCString()); + } + else + { + return NULL; + } +} + +Dictionary* Dictionary::create() +{ + Dictionary* ret = new Dictionary(); + if (ret && ret->init() ) + { + ret->autorelease(); + } + return ret; +} + +bool Dictionary::init() +{ + return true; +} + +Dictionary* Dictionary::createWithDictionary(Dictionary* srcDict) +{ + return srcDict->clone(); +} + +Dictionary* Dictionary::createWithContentsOfFileThreadSafe(const char *pFileName) +{ + return FileUtils::getInstance()->createDictionaryWithContentsOfFile(pFileName); +} + +void Dictionary::acceptVisitor(DataVisitor &visitor) +{ + return visitor.visit(this); +} + +Dictionary* Dictionary::createWithContentsOfFile(const char *pFileName) +{ + auto ret = createWithContentsOfFileThreadSafe(pFileName); + if (ret != nullptr) + { + ret->autorelease(); + } + return ret; +} + +bool Dictionary::writeToFile(const char *fullPath) +{ + return FileUtils::getInstance()->writeToFile(this, fullPath); +} + +Dictionary* Dictionary::clone() const +{ + Dictionary* newDict = Dictionary::create(); + + DictElement* element = NULL; + Object* tmpObj = NULL; + Clonable* obj = NULL; + if (_dictType == kDictInt) + { + CCDICT_FOREACH(this, element) + { + obj = dynamic_cast(element->getObject()); + if (obj) + { + tmpObj = dynamic_cast(obj->clone()); + if (tmpObj) + { + newDict->setObject(tmpObj, element->getIntKey()); + } + } + else + { + CCLOGWARN("%s isn't clonable.", typeid(*element->getObject()).name()); + } + } + } + else if (_dictType == kDictStr) + { + CCDICT_FOREACH(this, element) + { + obj = dynamic_cast(element->getObject()); + if (obj) + { + tmpObj = dynamic_cast(obj->clone()); + if (tmpObj) + { + newDict->setObject(tmpObj, element->getStrKey()); + } + } + else + { + CCLOGWARN("%s isn't clonable.", typeid(*element->getObject()).name()); + } + } + } + + return newDict; +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCDictionary.h b/cocos/base/cocoa/CCDictionary.h new file mode 100644 index 0000000000..b0f1c98a9c --- /dev/null +++ b/cocos/base/cocoa/CCDictionary.h @@ -0,0 +1,458 @@ +/**************************************************************************** +Copyright (c) 2012 - 2013 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CCDICTIONARY_H__ +#define __CCDICTIONARY_H__ + +#include "support/data_support/uthash.h" +#include "CCObject.h" +#include "CCArray.h" +#include "CCString.h" + +NS_CC_BEGIN + +class Dictionary; + +/** + * @addtogroup data_structures + * @{ + */ + + +/** + * DictElement is used for traversing Dictionary. + * + * A DictElement is one element of Dictionary, it contains two properties, key and object. + * Its key has two different type (integer and string). + * + * @note The key type is unique, all the elements in Dictionary has the same key type(integer or string). + * @code + * DictElement* pElement; + * CCDICT_FOREACH(dict, pElement) + * { + * const char*key = pElement->getStrKey(); + * // You certainly know the type of value, so we assume that it's a Sprite. + * Sprite* pSprite = static_cast(pElement->getObject()); + * // ...... + * } + * @endcode + * + */ +class CC_DLL DictElement +{ +private: + /** + * Constructor of DictElement. It's only for internal usage. Dictionary is its friend class. + * + * @param pszKey The string key of this element. + * @param pObject The object of this element. + */ + DictElement(const char* pszKey, Object* pObject); + + /** + * Constructor of DictElement. It's only for internal usage. Dictionary is its friend class. + * + * @param iKey The integer key of this element. + * @param pObject The object of this element. + */ + DictElement(intptr_t iKey, Object* pObject); + +public: + /** + * The destructor of DictElement. + * @js NA + * @lua NA + */ + ~DictElement(); + + // Inline functions need to be implemented in header file on Android. + + /** + * Get the string key of this element. + * @note This method assumes you know the key type in the element. + * If the element's key type is integer, invoking this method will cause an assert. + * + * @return The string key of this element. + */ + inline const char* getStrKey() const + { + CCASSERT(_strKey[0] != '\0', "Should not call this function for integer dictionary"); + return _strKey; + } + + /** + * Get the integer key of this element. + * @note This method assumes you know the key type in the element. + * If the element's key type is string, invoking this method will cause an assert. + * + * @return The integer key of this element. + */ + inline intptr_t getIntKey() const + { + CCASSERT(_strKey[0] == '\0', "Should not call this function for string dictionary"); + return _intKey; + } + + /** + * Get the object of this element. + * + * @return The object of this element. + */ + inline Object* getObject() const { return _object; } + +private: + // The max length of string key. + #define MAX_KEY_LEN 256 + // char array is needed for HASH_ADD_STR in UT_HASH. + // So it's a pain that all elements will allocate 256 bytes for this array. + char _strKey[MAX_KEY_LEN]; // hash key of string type + intptr_t _intKey; // hash key of integer type + Object* _object; // hash value +public: + UT_hash_handle hh; // makes this class hashable + friend class Dictionary; // declare Dictionary as friend class +}; + +/** The macro for traversing dictionary + * + * @note It's faster than getting all keys and traversing keys to get objects by objectForKey. + * It's also safe to remove elements while traversing. + */ +#define CCDICT_FOREACH(__dict__, __el__) \ + DictElement* pTmp##__dict__##__el__ = nullptr; \ + if (__dict__) \ + HASH_ITER(hh, (__dict__)->_elements, __el__, pTmp##__dict__##__el__) + + + +/** + * Dictionary is a class like NSDictionary in Obj-C . + * + * @note Only the pointer of Object or its subclass can be inserted to Dictionary. + * @code + * // Create a dictionary, return an autorelease object. + * Dictionary* pDict = Dictionary::create(); + * + * // Insert objects to dictionary + * String* pValue1 = String::create("100"); + * String* pValue2 = String::create("120"); + * Integer* pValue3 = Integer::create(200); + * pDict->setObject(pValue1, "key1"); + * pDict->setObject(pValue2, "key2"); + * pDict->setObject(pValue3, "key3"); + * + * // Get the object for key + * String* pStr1 = (String*)pDict->objectForKey("key1"); + * log("{ key1: %s }", pStr1->getCString()); + * Integer* pInteger = (Integer*)pDict->objectForKey("key3"); + * log("{ key3: %d }", pInteger->getValue()); + * @endcode + * + */ + +class CC_DLL Dictionary : public Object, public Clonable +{ +public: + /** + * The constructor of Dictionary. + * @js NA + * @lua NA + */ + Dictionary(); + + /** + * The destructor of Dictionary + * @js NA + * @lua NA + */ + ~Dictionary(); + + /** Initializes the dictionary. It returns true if the initializations was successful. + * @js NA + * @lua NA + */ + bool init(); + /** + * Get the count of elements in Dictionary. + * + * @return The count of elements. + * @js NA + */ + unsigned int count(); + + /** + * Return all keys of elements. + * + * @return The array contains all keys of elements. It's an autorelease object yet. + * @js NA + */ + Array* allKeys(); + + /** + * Get all keys according to the specified object. + * @warning We use '==' to compare two objects + * @return The array contains all keys for the specified object. It's an autorelease object yet. + * @js NA + */ + Array* allKeysForObject(Object* object); + + /** + * Get the object according to the specified string key. + * + * @note The dictionary needs to use string as key. If integer is passed, an assert will appear. + * @param key The string key for searching. + * @return The object matches the key. You need to force convert it to the type you know. + * @code + * // Assume that the elements are String* pointers. Convert it by following code. + * String* pStr = (String*)pDict->objectForKey("key1"); + * // Do something about pStr. + * // If you don't know the object type, properly you need to use dynamic_cast to check it. + * String* pStr2 = dynamic_cast(pDict->objectForKey("key1")); + * if (pStr2 != NULL) { + * // Do something about pStr2 + * } + * @endcode + * @see objectForKey(intptr_t) + * @js NA + */ + Object* objectForKey(const std::string& key); + + /** + * Get the object according to the specified integer key. + * + * @note The dictionary needs to use integer as key. If string is passed, an assert will appear. + * @param key The integer key for searching. + * @return The object matches the key. + * @see objectForKey(const std::string&) + * @js NA + */ + Object* objectForKey(intptr_t key); + + /** Get the value according to the specified string key. + * + * @note Be careful to use this function since it assumes the objects in the dictionary are String pointer. + * @param key The string key for searching + * @return An instance of String. + * It will return an empty string if the objects aren't String pointer or the key wasn't found. + * @see valueForKey(intptr_t) + * @js NA + */ + const String* valueForKey(const std::string& key); + + /** Get the value according to the specified integer key. + * + * @note Be careful to use this function since it assumes the objects in the dictionary are String pointer. + * @param key The string key for searching. + * @return An instance of String. + * It will return an empty string if the objects aren't String pointer or the key wasn't found. + * @see valueForKey(intptr_t) + * @js NA + */ + const String* valueForKey(intptr_t key); + + /** Insert an object to dictionary, and match it with the specified string key. + * + * @note Whe the first time this method is invoked, the key type will be set to string. + * After that you can't setObject with an integer key. + * If the dictionary contains the key you passed, the object matching the key will be released and removed from dictionary. + * Then the new object will be inserted after that. + * + * @param pObject The Object to be inserted. + * @param key The string key for searching. + * @see setObject(Object*, intptr_t) + * @js NA + */ + void setObject(Object* pObject, const std::string& key); + + /** Insert an object to dictionary, and match it with the specified string key. + * + * @note Then the first time this method is invoked, the key type will be set to string. + * After that you can't setObject with an integer key. + * If the dictionary contains the key you passed, the object matching the key will be released and removed from dictionary. + * Then the new object will be inserted after that. + * @param pObject The Object to be inserted. + * @param key The string key for searching. + * @see setObject(Object*, const std::string&) + * @js NA + */ + void setObject(Object* pObject, intptr_t key); + + /** + * Remove an object by the specified string key. + * + * @param key The string key for searching. + * @see removeObjectForKey(intptr_t), removeObjectsForKeys(Array*), + * removeObjectForElememt(DictElement*), removeAllObjects(). + * @js NA + */ + void removeObjectForKey(const std::string& key); + + /** + * Remove an object by the specified integer key. + * + * @param key The integer key for searching. + * @see removeObjectForKey(const std::string&), removeObjectsForKeys(Array*), + * removeObjectForElememt(DictElement*), removeAllObjects(). + * @js NA + */ + void removeObjectForKey(intptr_t key); + + /** + * Remove objects by an array of keys. + * + * @param pKeyArray The array contains keys to be removed. + * @see removeObjectForKey(const std::string&), removeObjectForKey(intptr_t), + * removeObjectForElememt(DictElement*), removeAllObjects(). + * @js NA + */ + void removeObjectsForKeys(Array* pKeyArray); + + /** + * Remove an object by an element. + * + * @param pElement The element need to be removed. + * @see removeObjectForKey(const std::string&), removeObjectForKey(intptr_t), + * removeObjectsForKeys(Array*), removeAllObjects(). + * @js NA + * @lua NA + */ + void removeObjectForElememt(DictElement* pElement); + + /** + * Remove all objects in the dictionary. + * + * @see removeObjectForKey(const std::string&), removeObjectForKey(intptr_t), + * removeObjectsForKeys(Array*), removeObjectForElememt(DictElement*). + * @js NA + */ + void removeAllObjects(); + + /** + * Return a random object in the dictionary. + * + * @return The random object. + * @see objectForKey(intptr_t), objectForKey(const std::string&) + * @js NA + * @lua NA + */ + Object* randomObject(); + + /** + * Create a dictionary. + * @return A dictionary which is an autorelease object. + * @see createWithDictionary(Dictionary*), createWithContentsOfFile(const char*), createWithContentsOfFileThreadSafe(const char*). + * @js NA + */ + static Dictionary* create(); + + /** + * Create a dictionary with an existing dictionary. + * + * @param srcDict The exist dictionary. + * @return A dictionary which is an autorelease object. + * @see create(), createWithContentsOfFile(const char*), createWithContentsOfFileThreadSafe(const char*). + * @js NA + */ + static Dictionary* createWithDictionary(Dictionary* srcDict); + + /** + * Create a dictionary with a plist file. + * @param pFileName The name of the plist file. + * @return A dictionary which is an autorelease object. + * @see create(), createWithDictionary(Dictionary*), createWithContentsOfFileThreadSafe(const char*). + * @js NA + */ + static Dictionary* createWithContentsOfFile(const char *pFileName); + + /** + * Write a dictionary to a plist file. + * @param fullPath The full path of the plist file. You can get writeable path by getWritablePath() + * @return true if successed, false if failed + * @js NA + * @lua NA + */ + bool writeToFile(const char *fullPath); + + /** + * Create a dictionary with a plist file. + * + * @note the return object isn't an autorelease object. + * This can make sure not using autorelease pool in a new thread. + * Therefore, you need to manage the lifecycle of the return object. + * It means that when you don't need it, CC_SAFE_RELEASE needs to be invoked. + * + * @param pFileName The name of the plist file. + * @return A dictionary which isn't an autorelease object. + * @js NA + * @lua NA + */ + static Dictionary* createWithContentsOfFileThreadSafe(const char *pFileName); + + /* override functions + * @js NA + * @lua NA + */ + virtual void acceptVisitor(DataVisitor &visitor); + /** + * @js NA + * @lua NA + */ + virtual Dictionary* clone() const; + +private: + /** + * For internal usage, invoked by setObject. + */ + void setObjectUnSafe(Object* pObject, const std::string& key); + void setObjectUnSafe(Object* pObject, const intptr_t key); + +public: + /** + * All the elements in dictionary. + * + * @note For internal usage, we need to declare this member variable as public since it's used in UT_HASH. + */ + DictElement* _elements; +private: + + /** The support type of dictionary, it's confirmed when setObject is invoked. */ + enum DictType + { + kDictUnknown = 0, + kDictStr, + kDictInt + }; + + /** + * The type of dictionary, it's assigned to kDictUnknown by default. + */ + DictType _dictType; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif /* __CCDICTIONARY_H__ */ diff --git a/cocos/base/cocoa/CCDouble.h b/cocos/base/cocoa/CCDouble.h new file mode 100644 index 0000000000..5b45b1d6cf --- /dev/null +++ b/cocos/base/cocoa/CCDouble.h @@ -0,0 +1,70 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCDOUBLE_H__ +#define __CCDOUBLE_H__ + +#include "CCObject.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +class CC_DLL Double : public Object, public Clonable +{ +public: + Double(double v) + : _value(v) {} + double getValue() const {return _value;} + + static Double* create(double v) + { + Double* pRet = new Double(v); + if (pRet) + { + pRet->autorelease(); + } + return pRet; + } + + /* override functions */ + virtual void acceptVisitor(DataVisitor &visitor) { visitor.visit(this); } + + Double* clone() const + { + return Double::create(_value); + } +private: + double _value; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif /* __CCDOUBLE_H__ */ diff --git a/cocos/base/cocoa/CCFloat.h b/cocos/base/cocoa/CCFloat.h new file mode 100644 index 0000000000..c85a2e1e70 --- /dev/null +++ b/cocos/base/cocoa/CCFloat.h @@ -0,0 +1,71 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCFLOAT_H__ +#define __CCFLOAT_H__ + +#include "CCObject.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +class CC_DLL Float : public Object, public Clonable +{ +public: + Float(float v) + : _value(v) {} + float getValue() const {return _value;} + + static Float* create(float v) + { + Float* pRet = new Float(v); + if (pRet) + { + pRet->autorelease(); + } + return pRet; + } + + /* override functions */ + virtual void acceptVisitor(DataVisitor &visitor) { visitor.visit(this); } + + Float* clone() const + { + return Float::create(_value); + } + +private: + float _value; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif /* __CCFLOAT_H__ */ diff --git a/cocos/base/cocoa/CCGeometry.cpp b/cocos/base/cocoa/CCGeometry.cpp new file mode 100644 index 0000000000..cfce9d3fa7 --- /dev/null +++ b/cocos/base/cocoa/CCGeometry.cpp @@ -0,0 +1,463 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#include "CCGeometry.h" +#include "ccMacros.h" +#include + +// implementation of Point +NS_CC_BEGIN + +Point::Point(void) : x(0), y(0) +{ +} + +Point::Point(float xx, float yy) : x(xx), y(yy) +{ +} + +Point::Point(const Point& other) : x(other.x), y(other.y) +{ +} + +Point::Point(const Size& size) : x(size.width), y(size.height) +{ +} + +Point& Point::operator= (const Point& other) +{ + setPoint(other.x, other.y); + return *this; +} + +Point& Point::operator= (const Size& size) +{ + setPoint(size.width, size.height); + return *this; +} + +Point Point::operator+(const Point& right) const +{ + return Point(this->x + right.x, this->y + right.y); +} + +Point Point::operator-(const Point& right) const +{ + return Point(this->x - right.x, this->y - right.y); +} + +Point Point::operator-() const +{ + return Point(-x, -y); +} + +Point Point::operator*(float a) const +{ + return Point(this->x * a, this->y * a); +} + +Point Point::operator/(float a) const +{ + CCASSERT(a!=0, "CCPoint division by 0."); + return Point(this->x / a, this->y / a); +} + +void Point::setPoint(float xx, float yy) +{ + this->x = xx; + this->y = yy; +} + +bool Point::equals(const Point& target) const +{ + return (fabs(this->x - target.x) < FLT_EPSILON) + && (fabs(this->y - target.y) < FLT_EPSILON); +} + +bool Point::fuzzyEquals(const Point& b, float var) const +{ + if(x - var <= b.x && b.x <= x + var) + if(y - var <= b.y && b.y <= y + var) + return true; + return false; +} + +float Point::getAngle(const Point& other) const +{ + Point a2 = normalize(); + Point b2 = other.normalize(); + float angle = atan2f(a2.cross(b2), a2.dot(b2)); + if( fabs(angle) < FLT_EPSILON ) return 0.f; + return angle; +} + +Point Point::rotateByAngle(const Point& pivot, float angle) const +{ + return pivot + (*this - pivot).rotate(Point::forAngle(angle)); +} + +bool Point::isOneDemensionSegmentOverlap(float A, float B, float C, float D, float *S, float *E) +{ + float ABmin = MIN(A, B); + float ABmax = MAX(A, B); + float CDmin = MIN(C, D); + float CDmax = MAX(C, D); + + if (ABmax < CDmin || CDmax < ABmin) + { + // ABmin->ABmax->CDmin->CDmax or CDmin->CDmax->ABmin->ABmax + return false; + } + else + { + if (ABmin >= CDmin && ABmin <= CDmax) + { + // CDmin->ABmin->CDmax->ABmax or CDmin->ABmin->ABmax->CDmax + if (S != nullptr) *S = ABmin; + if (E != nullptr) *E = CDmax < ABmax ? CDmax : ABmax; + } + else if (ABmax >= CDmin && ABmax <= CDmax) + { + // ABmin->CDmin->ABmax->CDmax + if (S != nullptr) *S = CDmin; + if (E != nullptr) *E = ABmax; + } + else + { + // ABmin->CDmin->CDmax->ABmax + if (S != nullptr) *S = CDmin; + if (E != nullptr) *E = CDmax; + } + return true; + } +} + +bool Point::isLineIntersect(const Point& A, const Point& B, + const Point& C, const Point& D, + float *S, float *T) +{ + // FAIL: Line undefined + if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) + { + return false; + } + + const float denom = crossProduct2Vector(A, B, C, D); + + if (denom == 0) + { + // Lines parallel or overlap + return false; + } + + if (S != nullptr) *S = crossProduct2Vector(C, D, C, A) / denom; + if (T != nullptr) *T = crossProduct2Vector(A, B, C, A) / denom; + + return true; +} + +bool Point::isLineParallel(const Point& A, const Point& B, + const Point& C, const Point& D) +{ + // FAIL: Line undefined + if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) + { + return false; + } + + if (crossProduct2Vector(A, B, C, D) == 0) + { + // line overlap + if (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0) + { + return false; + } + + return true; + } + + return false; +} + +bool Point::isLineOverlap(const Point& A, const Point& B, + const Point& C, const Point& D) +{ + // FAIL: Line undefined + if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) + { + return false; + } + + if (crossProduct2Vector(A, B, C, D) == 0 && + (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0)) + { + return true; + } + + return false; +} + +bool Point::isSegmentOverlap(const Point& A, const Point& B, const Point& C, const Point& D, Point* S, Point* E) +{ + + if (isLineOverlap(A, B, C, D)) + { + return isOneDemensionSegmentOverlap(A.x, B.x, C.x, D.x, &S->x, &E->x) && + isOneDemensionSegmentOverlap(A.y, B.y, C.y, D.y, &S->y, &E->y); + } + + return false; +} + +bool Point::isSegmentIntersect(const Point& A, const Point& B, const Point& C, const Point& D) +{ + float S, T; + + if (isLineIntersect(A, B, C, D, &S, &T )&& + (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f)) + { + return true; + } + + return false; +} + +Point Point::getIntersectPoint(const Point& A, const Point& B, const Point& C, const Point& D) +{ + float S, T; + + if (isLineIntersect(A, B, C, D, &S, &T)) + { + // Point of intersection + Point P; + P.x = A.x + S * (B.x - A.x); + P.y = A.y + S * (B.y - A.y); + return P; + } + + return Point::ZERO; +} + +const Point Point::ZERO = Point(0, 0); + +// implementation of Size + +Size::Size(void) : width(0), height(0) +{ +} + +Size::Size(float w, float h) : width(w), height(h) +{ +} + +Size::Size(const Size& other) : width(other.width), height(other.height) +{ +} + +Size::Size(const Point& point) : width(point.x), height(point.y) +{ +} + +Size& Size::operator= (const Size& other) +{ + setSize(other.width, other.height); + return *this; +} + +Size& Size::operator= (const Point& point) +{ + setSize(point.x, point.y); + return *this; +} + +Size Size::operator+(const Size& right) const +{ + return Size(this->width + right.width, this->height + right.height); +} + +Size Size::operator-(const Size& right) const +{ + return Size(this->width - right.width, this->height - right.height); +} + +Size Size::operator*(float a) const +{ + return Size(this->width * a, this->height * a); +} + +Size Size::operator/(float a) const +{ + CCASSERT(a!=0, "CCSize division by 0."); + return Size(this->width / a, this->height / a); +} + +void Size::setSize(float w, float h) +{ + this->width = w; + this->height = h; +} + +bool Size::equals(const Size& target) const +{ + return (fabs(this->width - target.width) < FLT_EPSILON) + && (fabs(this->height - target.height) < FLT_EPSILON); +} + +const Size Size::ZERO = Size(0, 0); + +// implementation of Rect + +Rect::Rect(void) +{ + setRect(0.0f, 0.0f, 0.0f, 0.0f); +} + +Rect::Rect(float x, float y, float width, float height) +{ + setRect(x, y, width, height); +} + +Rect::Rect(const Rect& other) +{ + setRect(other.origin.x, other.origin.y, other.size.width, other.size.height); +} + +Rect& Rect::operator= (const Rect& other) +{ + setRect(other.origin.x, other.origin.y, other.size.width, other.size.height); + return *this; +} + +void Rect::setRect(float x, float y, float width, float height) +{ + // CGRect can support width<0 or height<0 + // CCASSERT(width >= 0.0f && height >= 0.0f, "width and height of Rect must not less than 0."); + + origin.x = x; + origin.y = y; + + size.width = width; + size.height = height; +} + +bool Rect::equals(const Rect& rect) const +{ + return (origin.equals(rect.origin) && + size.equals(rect.size)); +} + +float Rect::getMaxX() const +{ + return origin.x + size.width; +} + +float Rect::getMidX() const +{ + return origin.x + size.width / 2.0f; +} + +float Rect::getMinX() const +{ + return origin.x; +} + +float Rect::getMaxY() const +{ + return origin.y + size.height; +} + +float Rect::getMidY() const +{ + return origin.y + size.height / 2.0f; +} + +float Rect::getMinY() const +{ + return origin.y; +} + +bool Rect::containsPoint(const Point& point) const +{ + bool bRet = false; + + if (point.x >= getMinX() && point.x <= getMaxX() + && point.y >= getMinY() && point.y <= getMaxY()) + { + bRet = true; + } + + return bRet; +} + +bool Rect::intersectsRect(const Rect& rect) const +{ + return !( getMaxX() < rect.getMinX() || + rect.getMaxX() < getMinX() || + getMaxY() < rect.getMinY() || + rect.getMaxY() < getMinY()); +} + +Rect Rect::unionWithRect(const Rect & rect) const +{ + float thisLeftX = origin.x; + float thisRightX = origin.x + size.width; + float thisTopY = origin.y + size.height; + float thisBottomY = origin.y; + + if (thisRightX < thisLeftX) + { + std::swap(thisRightX, thisLeftX); // This rect has negative width + } + + if (thisTopY < thisBottomY) + { + std::swap(thisTopY, thisBottomY); // This rect has negative height + } + + float otherLeftX = rect.origin.x; + float otherRightX = rect.origin.x + rect.size.width; + float otherTopY = rect.origin.y + rect.size.height; + float otherBottomY = rect.origin.y; + + if (otherRightX < otherLeftX) + { + std::swap(otherRightX, otherLeftX); // Other rect has negative width + } + + if (otherTopY < otherBottomY) + { + std::swap(otherTopY, otherBottomY); // Other rect has negative height + } + + float combinedLeftX = std::min(thisLeftX, otherLeftX); + float combinedRightX = std::max(thisRightX, otherRightX); + float combinedTopY = std::max(thisTopY, otherTopY); + float combinedBottomY = std::min(thisBottomY, otherBottomY); + + return Rect(combinedLeftX, combinedBottomY, combinedRightX - combinedLeftX, combinedTopY - combinedBottomY); +} + +const Rect Rect::ZERO = Rect(0, 0, 0, 0); + +NS_CC_END diff --git a/cocos/base/cocoa/CCGeometry.h b/cocos/base/cocoa/CCGeometry.h new file mode 100644 index 0000000000..47e2fdf9ac --- /dev/null +++ b/cocos/base/cocoa/CCGeometry.h @@ -0,0 +1,564 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CCGEMETRY_H__ +#define __CCGEMETRY_H__ + +#include +#include + +#include "platform/CCPlatformMacros.h" +#include "CCObject.h" +#include "ccMacros.h" + +NS_CC_BEGIN + +/** Clamp a value between from and to. + @since v0.99.1 + */ +inline float clampf(float value, float min_inclusive, float max_inclusive) +{ + if (min_inclusive > max_inclusive) { + CC_SWAP(min_inclusive, max_inclusive, float); + } + return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive; +} + +/** + * @addtogroup data_structures + * @{ + */ + +// for Point assignement operator and copy constructor +class CC_DLL Size; + +class CC_DLL Point +{ +public: + float x; + float y; + +public: + /** + * @js NA + */ + Point(); + /** + * @js NA + */ + Point(float x, float y); + /** + * @js NA + * @lua NA + */ + Point(const Point& other); + /** + * @js NA + * @lua NA + */ + explicit Point(const Size& size); + /** + * @js NA + * @lua NA + */ + Point& operator= (const Point& other); + /** + * @js NA + * @lua NA + */ + Point& operator= (const Size& size); + /** + * @js NA + * @lua NA + */ + Point operator+(const Point& right) const; + /** + * @js NA + * @lua NA + */ + Point operator-(const Point& right) const; + /** + * @js NA + * @lua NA + */ + Point operator-() const; + /** + * @js NA + * @lua NA + */ + Point operator*(float a) const; + /** + * @js NA + * @lua NA + */ + Point operator/(float a) const; + /** + * @js NA + * @lua NA + */ + void setPoint(float x, float y); + /** + * @js NA + */ + bool equals(const Point& target) const; + + /** @returns if points have fuzzy equality which means equal with some degree of variance. + @since v2.1.4 + * @js NA + * @lua NA + */ + bool fuzzyEquals(const Point& target, float variance) const; + + /** Calculates distance between point an origin + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float getLength() const { + return sqrtf(x*x + y*y); + }; + + /** Calculates the square length of a Point (not calling sqrt() ) + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float getLengthSq() const { + return dot(*this); //x*x + y*y; + }; + + /** Calculates the square distance between two points (not calling sqrt() ) + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float getDistanceSq(const Point& other) const { + return (*this - other).getLengthSq(); + }; + + /** Calculates the distance between two points + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float getDistance(const Point& other) const { + return (*this - other).getLength(); + }; + + /** @returns the angle in radians between this vector and the x axis + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float getAngle() const { + return atan2f(y, x); + }; + + /** @returns the angle in radians between two vector directions + @since v2.1.4 + * @js NA + * @lua NA + */ + float getAngle(const Point& other) const; + + /** Calculates dot product of two points. + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float dot(const Point& other) const { + return x*other.x + y*other.y; + }; + + /** Calculates cross product of two points. + @return float + @since v2.1.4 + * @js NA + * @lua NA + */ + inline float cross(const Point& other) const { + return x*other.y - y*other.x; + }; + + /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 + @return Point + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point getPerp() const { + return Point(-y, x); + }; + + /** Calculates midpoint between two points. + @return Point + @since v3.0 + * @js NA + * @lua NA + */ + inline Point getMidpoint(const Point& other) const + { + return Point((x + other.x) / 2.0f, (y + other.y) / 2.0f); + } + + /** Clamp a point between from and to. + @since v3.0 + * @js NA + * @lua NA + */ + inline Point getClampPoint(const Point& min_inclusive, const Point& max_inclusive) const + { + return Point(clampf(x,min_inclusive.x,max_inclusive.x), clampf(y, min_inclusive.y, max_inclusive.y)); + } + + /** Run a math operation function on each point component + * absf, fllorf, ceilf, roundf + * any function that has the signature: float func(float); + * For example: let's try to take the floor of x,y + * p.compOp(floorf); + @since v3.0 + * @js NA + * @lua NA + */ + inline Point compOp(std::function function) const + { + return Point(function(x), function(y)); + } + + /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 + @return Point + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point getRPerp() const { + return Point(y, -x); + }; + + /** Calculates the projection of this over other. + @return Point + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point project(const Point& other) const { + return other * (dot(other)/other.dot(other)); + }; + + /** Complex multiplication of two points ("rotates" two points). + @return Point vector with an angle of this.getAngle() + other.getAngle(), + and a length of this.getLength() * other.getLength(). + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point rotate(const Point& other) const { + return Point(x*other.x - y*other.y, x*other.y + y*other.x); + }; + + /** Unrotates two points. + @return Point vector with an angle of this.getAngle() - other.getAngle(), + and a length of this.getLength() * other.getLength(). + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point unrotate(const Point& other) const { + return Point(x*other.x + y*other.y, y*other.x - x*other.y); + }; + + /** Returns point multiplied to a length of 1. + * If the point is 0, it returns (1, 0) + @return Point + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point normalize() const { + float length = getLength(); + if(length == 0.) return Point(1.f, 0); + return *this / getLength(); + }; + + /** Linear Interpolation between two points a and b + @returns + alpha == 0 ? a + alpha == 1 ? b + otherwise a value between a..b + @since v2.1.4 + * @js NA + * @lua NA + */ + inline Point lerp(const Point& other, float alpha) const { + return *this * (1.f - alpha) + other * alpha; + }; + + /** Rotates a point counter clockwise by the angle around a pivot + @param pivot is the pivot, naturally + @param angle is the angle of rotation ccw in radians + @returns the rotated point + @since v2.1.4 + * @js NA + * @lua NA + */ + Point rotateByAngle(const Point& pivot, float angle) const; + + /** + * @js NA + * @lua NA + */ + static inline Point forAngle(const float a) + { + return Point(cosf(a), sinf(a)); + } + + /** A general line-line intersection test + @param A the startpoint for the first line L1 = (A - B) + @param B the endpoint for the first line L1 = (A - B) + @param C the startpoint for the second line L2 = (C - D) + @param D the endpoint for the second line L2 = (C - D) + @param S the range for a hitpoint in L1 (p = A + S*(B - A)) + @param T the range for a hitpoint in L2 (p = C + T*(D - C)) + @returns whether these two lines interects. + + Note that to truly test intersection for segments we have to make + sure that S & T lie within [0..1] and for rays, make sure S & T > 0 + the hit point is C + T * (D - C); + the hit point also is A + S * (B - A); + @since 3.0 + * @js NA + * @lua NA + */ + static bool isLineIntersect(const Point& A, const Point& B, + const Point& C, const Point& D, + float *S = nullptr, float *T = nullptr); + + /** + returns true if Line A-B overlap with segment C-D + @since v3.0 + * @js NA + * @lua NA + */ + static bool isLineOverlap(const Point& A, const Point& B, + const Point& C, const Point& D); + + /** + returns true if Line A-B parallel with segment C-D + @since v3.0 + * @js NA + * @lua NA + */ + static bool isLineParallel(const Point& A, const Point& B, + const Point& C, const Point& D); + + /** + returns true if Segment A-B overlap with segment C-D + @since v3.0 + * @js NA + * @lua NA + */ + static bool isSegmentOverlap(const Point& A, const Point& B, + const Point& C, const Point& D, + Point* S = nullptr, Point* E = nullptr); + + /** + returns true if Segment A-B intersects with segment C-D + @since v3.0 + * @js NA + * @lua NA + */ + static bool isSegmentIntersect(const Point& A, const Point& B, const Point& C, const Point& D); + + /** + returns the intersection point of line A-B, C-D + @since v3.0 + * @js NA + * @lua NA + */ + static Point getIntersectPoint(const Point& A, const Point& B, const Point& C, const Point& D); + + static const Point ZERO; + +private: + // returns true if segment A-B intersects with segment C-D. S->E is the ovderlap part + static bool isOneDemensionSegmentOverlap(float A, float B, float C, float D, float *S, float * E); + + // cross procuct of 2 vector. A->B X C->D + static float crossProduct2Vector(const Point& A, const Point& B, const Point& C, const Point& D) { return (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y); } +}; + +class CC_DLL Size +{ +public: + float width; + float height; + +public: + /** + * @js NA + */ + Size(); + /** + * @js NA + */ + Size(float width, float height); + /** + * @js NA + * @lua NA + */ + Size(const Size& other); + /** + * @js NA + * @lua NA + */ + explicit Size(const Point& point); + /** + * @js NA + * @lua NA + */ + Size& operator= (const Size& other); + /** + * @js NA + * @lua NA + */ + Size& operator= (const Point& point); + /** + * @js NA + * @lua NA + */ + Size operator+(const Size& right) const; + /** + * @js NA + * @lua NA + */ + Size operator-(const Size& right) const; + /** + * @js NA + * @lua NA + */ + Size operator*(float a) const; + /** + * @js NA + * @lua NA + */ + Size operator/(float a) const; + /** + * @js NA + * @lua NA + */ + void setSize(float width, float height); + /** + * @js NA + */ + bool equals(const Size& target) const; + + static const Size ZERO; +}; + +class CC_DLL Rect +{ +public: + Point origin; + Size size; + +public: + /** + * @js NA + */ + Rect(); + /** + * @js NA + */ + Rect(float x, float y, float width, float height); + /** + * @js NA + * @lua NA + */ + Rect(const Rect& other); + /** + * @js NA + * @lua NA + */ + Rect& operator= (const Rect& other); + /** + * @js NA + * @lua NA + */ + void setRect(float x, float y, float width, float height); + /** + * @js NA + */ + float getMinX() const; /// return the leftmost x-value of current rect + /** + * @js NA + */ + float getMidX() const; /// return the midpoint x-value of current rect + /** + * @js NA + */ + float getMaxX() const; /// return the rightmost x-value of current rect + /** + * @js NA + */ + float getMinY() const; /// return the bottommost y-value of current rect + /** + * @js NA + */ + float getMidY() const; /// return the midpoint y-value of current rect + /** + * @js NA + */ + float getMaxY() const; /// return the topmost y-value of current rect + /** + * @js NA + */ + bool equals(const Rect& rect) const; + /** + * @js NA + */ + bool containsPoint(const Point& point) const; + /** + * @js NA + */ + bool intersectsRect(const Rect& rect) const; + /** + * @js NA + * @lua NA + */ + Rect unionWithRect(const Rect & rect) const; + + static const Rect ZERO; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif // __CCGEMETRY_H__ diff --git a/cocos/base/cocoa/CCInteger.h b/cocos/base/cocoa/CCInteger.h new file mode 100644 index 0000000000..23735627dd --- /dev/null +++ b/cocos/base/cocoa/CCInteger.h @@ -0,0 +1,79 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __CCINTEGER_H__ +#define __CCINTEGER_H__ + +#include "CCObject.h" +#include "platform/CCCommon.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +class CC_DLL Integer : public Object, public Clonable +{ +public: + static Integer* create(int v) + { + Integer* pRet = new Integer(v); + pRet->autorelease(); + return pRet; + } + /** + * @js NA + */ + Integer(int v) + : _value(v) {} + int getValue() const {return _value;} + /** + * @js NA + * @lua NA + */ + virtual ~Integer() { + CCLOGINFO("deallocing ~Integer: %p", this); + } + + /* override functions */ + virtual void acceptVisitor(DataVisitor &visitor) { visitor.visit(this); } + + // overrides + virtual Integer* clone() const override + { + return Integer::create(_value); + } + +private: + int _value; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif /* __CCINTEGER_H__ */ diff --git a/cocos/base/cocoa/CCNS.cpp b/cocos/base/cocoa/CCNS.cpp new file mode 100644 index 0000000000..8cf496c0b1 --- /dev/null +++ b/cocos/base/cocoa/CCNS.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#include "CCNS.h" +#include +#include +#include +#include + +using namespace std; + +NS_CC_BEGIN + +typedef std::vector strArray; + +// string toolkit +static inline void split(std::string src, const char* token, strArray& vect) +{ + int nend=0; + int nbegin=0; + while(nend != -1) + { + nend = src.find(token, nbegin); + if(nend == -1) + vect.push_back(src.substr(nbegin, src.length()-nbegin)); + else + vect.push_back(src.substr(nbegin, nend-nbegin)); + nbegin = nend + strlen(token); + } +} + +// first, judge whether the form of the string like this: {x,y} +// if the form is right,the string will be split into the parameter strs; +// or the parameter strs will be empty. +// if the form is right return true,else return false. +static bool splitWithForm(const char* pStr, strArray& strs) +{ + bool bRet = false; + + do + { + CC_BREAK_IF(!pStr); + + // string is empty + std::string content = pStr; + CC_BREAK_IF(content.length() == 0); + + int nPosLeft = content.find('{'); + int nPosRight = content.find('}'); + + // don't have '{' and '}' + CC_BREAK_IF(nPosLeft == (int)std::string::npos || nPosRight == (int)std::string::npos); + // '}' is before '{' + CC_BREAK_IF(nPosLeft > nPosRight); + + std::string pointStr = content.substr(nPosLeft + 1, nPosRight - nPosLeft - 1); + // nothing between '{' and '}' + CC_BREAK_IF(pointStr.length() == 0); + + int nPos1 = pointStr.find('{'); + int nPos2 = pointStr.find('}'); + // contain '{' or '}' + CC_BREAK_IF(nPos1 != (int)std::string::npos || nPos2 != (int)std::string::npos); + + split(pointStr, ",", strs); + if (strs.size() != 2 || strs[0].length() == 0 || strs[1].length() == 0) + { + strs.clear(); + break; + } + + bRet = true; + } while (0); + + return bRet; +} + +// implement the functions + +Rect RectFromString(const char* pszContent) +{ + Rect result = Rect::ZERO; + + do + { + CC_BREAK_IF(!pszContent); + std::string content = pszContent; + + // find the first '{' and the third '}' + int nPosLeft = content.find('{'); + int nPosRight = content.find('}'); + for (int i = 1; i < 3; ++i) + { + if (nPosRight == (int)std::string::npos) + { + break; + } + nPosRight = content.find('}', nPosRight + 1); + } + CC_BREAK_IF(nPosLeft == (int)std::string::npos || nPosRight == (int)std::string::npos); + + content = content.substr(nPosLeft + 1, nPosRight - nPosLeft - 1); + int nPointEnd = content.find('}'); + CC_BREAK_IF(nPointEnd == (int)std::string::npos); + nPointEnd = content.find(',', nPointEnd); + CC_BREAK_IF(nPointEnd == (int)std::string::npos); + + // get the point string and size string + std::string pointStr = content.substr(0, nPointEnd); + std::string sizeStr = content.substr(nPointEnd + 1, content.length() - nPointEnd); + + // split the string with ',' + strArray pointInfo; + CC_BREAK_IF(!splitWithForm(pointStr.c_str(), pointInfo)); + strArray sizeInfo; + CC_BREAK_IF(!splitWithForm(sizeStr.c_str(), sizeInfo)); + + float x = (float) atof(pointInfo[0].c_str()); + float y = (float) atof(pointInfo[1].c_str()); + float width = (float) atof(sizeInfo[0].c_str()); + float height = (float) atof(sizeInfo[1].c_str()); + + result = Rect(x, y, width, height); + } while (0); + + return result; +} + +Point PointFromString(const char* pszContent) +{ + Point ret = Point::ZERO; + + do + { + strArray strs; + CC_BREAK_IF(!splitWithForm(pszContent, strs)); + + float x = (float) atof(strs[0].c_str()); + float y = (float) atof(strs[1].c_str()); + + ret = Point(x, y); + } while (0); + + return ret; +} + +Size SizeFromString(const char* pszContent) +{ + Size ret = Size::ZERO; + + do + { + strArray strs; + CC_BREAK_IF(!splitWithForm(pszContent, strs)); + + float width = (float) atof(strs[0].c_str()); + float height = (float) atof(strs[1].c_str()); + + ret = Size(width, height); + } while (0); + + return ret; +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCNS.h b/cocos/base/cocoa/CCNS.h new file mode 100644 index 0000000000..8ce8e1dde6 --- /dev/null +++ b/cocos/base/cocoa/CCNS.h @@ -0,0 +1,80 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __PLATFOMR_CCNS_H__ +#define __PLATFOMR_CCNS_H__ + +#include "CCGeometry.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +/** +@brief Returns a Core Graphics rectangle structure corresponding to the data in a given string. +@param pszContent A string object whose contents are of the form "{{x,y},{w, h}}", + where x is the x coordinate, y is the y coordinate, w is the width, and h is the height. + These components can represent integer or float values. + An example of a valid string is "{{3,2},{4,5}}". + The string is not localized, so items are always separated with a comma. +@return A Core Graphics structure that represents a rectangle. + If the string is not well-formed, the function returns Rect::ZERO. +*/ +Rect CC_DLL RectFromString(const char* pszContent); + +/** +@brief Returns a Core Graphics point structure corresponding to the data in a given string. +@param pszContent A string object whose contents are of the form "{x,y}", + where x is the x coordinate and y is the y coordinate. + The x and y values can represent integer or float values. + An example of a valid string is "{3.0,2.5}". + The string is not localized, so items are always separated with a comma. +@return A Core Graphics structure that represents a point. + If the string is not well-formed, the function returns Point::ZERO. +*/ +Point CC_DLL PointFromString(const char* pszContent); + +/** +@brief Returns a Core Graphics size structure corresponding to the data in a given string. +@param pszContent A string object whose contents are of the form "{w, h}", + where w is the width and h is the height. + The w and h values can be integer or float values. + An example of a valid string is "{3.0,2.5}". + The string is not localized, so items are always separated with a comma. +@return A Core Graphics structure that represents a size. + If the string is not well-formed, the function returns Size::ZERO. +*/ +Size CC_DLL SizeFromString(const char* pszContent); + +// end of data_structure group +/// @} + +NS_CC_END + +#endif // __PLATFOMR_CCNS_H__ + + diff --git a/cocos/base/cocoa/CCObject.cpp b/cocos/base/cocoa/CCObject.cpp new file mode 100644 index 0000000000..13fa0e3236 --- /dev/null +++ b/cocos/base/cocoa/CCObject.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + + +#include "CCObject.h" +#include "CCAutoreleasePool.h" +#include "ccMacros.h" +#include "script_support/CCScriptSupport.h" + +NS_CC_BEGIN + +Object::Object() +: _luaID(0) +, _reference(1) // when the object is created, the reference count of it is 1 +, _autoReleaseCount(0) +{ + static unsigned int uObjectCount = 0; + + _ID = ++uObjectCount; +} + +Object::~Object() +{ + // if the object is managed, we should remove it + // from pool manager + if (_autoReleaseCount > 0) + { + PoolManager::sharedPoolManager()->removeObject(this); + } + + // if the object is referenced by Lua engine, remove it + if (_luaID) + { + ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptObjectByObject(this); + } + else + { + ScriptEngineProtocol* pEngine = ScriptEngineManager::getInstance()->getScriptEngine(); + if (pEngine != NULL && pEngine->getScriptType() == kScriptTypeJavascript) + { + pEngine->removeScriptObjectByObject(this); + } + } +} + +Object* Object::autorelease() +{ + PoolManager::sharedPoolManager()->addObject(this); + return this; +} + +bool Object::isSingleReference() const +{ + return _reference == 1; +} + +unsigned int Object::retainCount() const +{ + return _reference; +} + +bool Object::isEqual(const Object *object) +{ + return this == object; +} + +void Object::acceptVisitor(DataVisitor &visitor) +{ + visitor.visitObject(this); +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCObject.h b/cocos/base/cocoa/CCObject.h new file mode 100644 index 0000000000..8de1ff9d8b --- /dev/null +++ b/cocos/base/cocoa/CCObject.h @@ -0,0 +1,216 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CCOBJECT_H__ +#define __CCOBJECT_H__ + +#include "cocoa/CCDataVisitor.h" +#include "ccMacros.h" + +#ifdef EMSCRIPTEN +#include +#endif // EMSCRIPTEN + +NS_CC_BEGIN + +/** + * @addtogroup base_nodes + * @{ + */ + +class Object; +class Node; + +/** Interface that defines how to clone an object */ +class CC_DLL Clonable +{ +public: + /** returns a copy of the object */ + virtual Clonable* clone() const = 0; + /** + * @js NA + * @lua NA + */ + virtual ~Clonable() {}; + + /** returns a copy of the object. + @deprecated Use clone() instead + */ + CC_DEPRECATED_ATTRIBUTE Object* copy() const + { + // use "clone" instead + CC_ASSERT(false); + return nullptr; + } +}; + +class CC_DLL Object +{ +public: + /// object id, ScriptSupport need public _ID + unsigned int _ID; + /// Lua reference id + int _luaID; +protected: + /// count of references + unsigned int _reference; + /// count of autorelease + unsigned int _autoReleaseCount; +public: + /** + * Constructor + * + * The object's reference count is 1 after construction. + * @js NA + */ + Object(); + + /** + * @js NA + * @lua NA + */ + virtual ~Object(); + + /** + * Release the ownership immediately. + * + * This decrements the object's reference count. + * + * If the reference count reaches 0 after the descrement, this object is + * destructed. + * + * @see retain, autorelease + * @js NA + */ + inline void release() + { + CCASSERT(_reference > 0, "reference count should greater than 0"); + --_reference; + + if (_reference == 0) + delete this; + } + + /** + * Retains the ownership. + * + * This increases the object's reference count. + * + * @see release, autorelease + * @js NA + */ + inline void retain() + { + CCASSERT(_reference > 0, "reference count should greater than 0"); + ++_reference; + } + + /** + * Release the ownership sometime soon automatically. + * + * This descrements the object's reference count at the end of current + * autorelease pool block. + * + * If the reference count reaches 0 after the descrement, this object is + * destructed. + * + * @returns The object itself. + * + * @see AutoreleasePool, retain, release + * @js NA + * @lua NA + */ + Object* autorelease(); + + /** + * Returns a boolean value that indicates whether there is only one + * reference to the object. That is, whether the reference count is 1. + * + * @returns Whether the object's reference count is 1. + * @js NA + */ + bool isSingleReference() const; + + /** + * Returns the object's current reference count. + * + * @returns The object's reference count. + * @js NA + */ + unsigned int retainCount() const; + + /** + * Returns a boolean value that indicates whether this object and a given + * object are equal. + * + * @param object The object to be compared to this object. + * + * @returns True if this object and @p object are equal, otherwise false. + * @js NA + * @lua NA + */ + virtual bool isEqual(const Object* object); + /** + * @js NA + * @lua NA + */ + virtual void acceptVisitor(DataVisitor &visitor); + /** + * @js NA + * @lua NA + */ + virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; + + friend class AutoreleasePool; +}; + + +typedef void (Object::*SEL_SCHEDULE)(float); +typedef void (Object::*SEL_CallFunc)(); +typedef void (Object::*SEL_CallFuncN)(Node*); +typedef void (Object::*SEL_CallFuncND)(Node*, void*); +typedef void (Object::*SEL_CallFuncO)(Object*); +typedef void (Object::*SEL_MenuHandler)(Object*); +typedef int (Object::*SEL_Compare)(Object*); + +#define schedule_selector(_SELECTOR) static_cast(&_SELECTOR) +#define callfunc_selector(_SELECTOR) static_cast(&_SELECTOR) +#define callfuncN_selector(_SELECTOR) static_cast(&_SELECTOR) +#define callfuncND_selector(_SELECTOR) static_cast(&_SELECTOR) +#define callfuncO_selector(_SELECTOR) static_cast(&_SELECTOR) +#define menu_selector(_SELECTOR) static_cast(&_SELECTOR) +#define event_selector(_SELECTOR) static_cast(&_SELECTOR) +#define compare_selector(_SELECTOR) static_cast(&_SELECTOR) + +// new callbacks based on C++11 +#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__) +#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__) +#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__) + +// end of base_nodes group +/// @} + +NS_CC_END + +#endif // __CCOBJECT_H__ diff --git a/cocos/base/cocoa/CCSet.cpp b/cocos/base/cocoa/CCSet.cpp new file mode 100644 index 0000000000..c3c24e0e5e --- /dev/null +++ b/cocos/base/cocoa/CCSet.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#include "CCSet.h" + +using namespace std; + +NS_CC_BEGIN + +Set::Set(void) +{ + _set = new set; +} + +Set::Set(const Set &rSetObject) +{ + _set = new set(*rSetObject._set); + + // call retain of members + SetIterator iter; + for (iter = _set->begin(); iter != _set->end(); ++iter) + { + if (! (*iter)) + { + break; + } + + (*iter)->retain(); + } +} + +Set::~Set(void) +{ + removeAllObjects(); + CC_SAFE_DELETE(_set); +} + +void Set::acceptVisitor(DataVisitor &visitor) +{ + visitor.visit(this); +} + +Set * Set::create() +{ + Set * pRet = new Set(); + + if (pRet != NULL) + { + pRet->autorelease(); + } + + return pRet; +} + +Set* Set::copy(void) +{ + Set *pSet = new Set(*this); + + return pSet; +} + +Set* Set::mutableCopy(void) +{ + return copy(); +} + +int Set::count(void) +{ + return (int)_set->size(); +} + +void Set::addObject(Object *pObject) +{ + if (_set->count(pObject) == 0) + { + CC_SAFE_RETAIN(pObject); + _set->insert(pObject); + } +} + +void Set::removeObject(Object *pObject) +{ + if (_set->erase(pObject) > 0) + { + CC_SAFE_RELEASE(pObject); + } +} + +void Set::removeAllObjects() +{ + SetIterator it = _set->begin(); + SetIterator tmp; + + while (it != _set->end()) + { + if (!(*it)) + { + break; + } + + tmp = it; + ++tmp; + Object * obj = *it; + _set->erase(it); + CC_SAFE_RELEASE(obj); + it = tmp; + } +} + +bool Set::containsObject(Object *pObject) +{ + return _set->find(pObject) != _set->end(); +} + +SetIterator Set::begin(void) +{ + return _set->begin(); +} + +SetIterator Set::end(void) +{ + return _set->end(); +} + +Object* Set::anyObject() +{ + if (!_set || _set->empty()) + { + return 0; + } + + SetIterator it; + + for( it = _set->begin(); it != _set->end(); ++it) + { + if (*it) + { + return (*it); + } + } + + return 0; +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCSet.h b/cocos/base/cocoa/CCSet.h new file mode 100644 index 0000000000..c748f0ada5 --- /dev/null +++ b/cocos/base/cocoa/CCSet.h @@ -0,0 +1,119 @@ +/**************************************************************************** +Copyright (c) 2010-2012 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef __CC_SET_H__ +#define __CC_SET_H__ + +#include +#include "CCObject.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +typedef std::set::iterator SetIterator; + +class CC_DLL Set : public Object +{ +public: + /** + * @js ctor + */ + Set(void); + Set(const Set &rSetObject); + /** + * @js NA + * @lua NA + */ + virtual ~Set(void); + + /** + * @brief Create and return a new empty set. + */ + static Set * create(); + + /** + *@brief Return a copy of the Set, it will copy all the elements. + */ + Set* copy(); + /** + *@brief It is the same as copy(). + */ + Set* mutableCopy(); + /** + *@brief Return the number of elements the Set contains. + */ + int count(); + /** + *@brief Add a element into Set, it will retain the element. + */ + void addObject(Object *pObject); + /** + *@brief Remove the given element, nothing todo if no element equals pObject. + */ + void removeObject(Object *pObject); + /** + *@brief Remove all elements of the set + */ + void removeAllObjects(); + /** + *@brief Check if Set contains a element equals pObject. + */ + bool containsObject(Object *pObject); + /** + *@brief Return the iterator that points to the first element. + * @js NA + * @lua NA + */ + SetIterator begin(); + /** + *@brief Return the iterator that points to the position after the last element. + * @js NA + * @lua NA + */ + SetIterator end(); + /** + *@brief Return the first element if it contains elements, or null if it doesn't contain any element. + */ + Object* anyObject(); + /** + * @js NA + * @lua NA + */ + virtual void acceptVisitor(DataVisitor &visitor); + +private: + std::set *_set; +}; + +// end of data_structure group +/// @} + +NS_CC_END + +#endif // __CC_SET_H__ + diff --git a/cocos/base/cocoa/CCString.cpp b/cocos/base/cocoa/CCString.cpp new file mode 100644 index 0000000000..f9962b1ba4 --- /dev/null +++ b/cocos/base/cocoa/CCString.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** + Copyright (c) 2010-2012 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "CCString.h" +#include "platform/CCFileUtils.h" +#include "ccMacros.h" +#include +#include +#include "CCArray.h" + +NS_CC_BEGIN + +#define kMaxStringLen (1024*100) + +String::String() + :_string("") +{} + +String::String(const char * str) + :_string(str) +{} + +String::String(const std::string& str) + :_string(str) +{} + +String::String(const String& str) + :_string(str.getCString()) +{} + +String::~String() +{ + CCLOGINFO("deallocing String: %p", this); + + _string.clear(); +} + +String& String::operator= (const String& other) +{ + _string = other._string; + return *this; +} + +bool String::initWithFormatAndValist(const char* format, va_list ap) +{ + bool bRet = false; + char* pBuf = (char*)malloc(kMaxStringLen); + if (pBuf != NULL) + { + vsnprintf(pBuf, kMaxStringLen, format, ap); + _string = pBuf; + free(pBuf); + bRet = true; + } + return bRet; +} + +bool String::initWithFormat(const char* format, ...) +{ + bool bRet = false; + _string.clear(); + + va_list ap; + va_start(ap, format); + + bRet = initWithFormatAndValist(format, ap); + + va_end(ap); + + return bRet; +} + +int String::intValue() const +{ + if (length() == 0) + { + return 0; + } + return atoi(_string.c_str()); +} + +unsigned int String::uintValue() const +{ + if (length() == 0) + { + return 0; + } + return (unsigned int)atoi(_string.c_str()); +} + +float String::floatValue() const +{ + if (length() == 0) + { + return 0.0f; + } + return (float)atof(_string.c_str()); +} + +double String::doubleValue() const +{ + if (length() == 0) + { + return 0.0; + } + return atof(_string.c_str()); +} + +bool String::boolValue() const +{ + if (length() == 0) + { + return false; + } + + if (0 == strcmp(_string.c_str(), "0") || 0 == strcmp(_string.c_str(), "false")) + { + return false; + } + return true; +} + +const char* String::getCString() const +{ + return _string.c_str(); +} + +unsigned int String::length() const +{ + return _string.length(); +} + +int String::compare(const char * pStr) const +{ + return strcmp(getCString(), pStr); +} + +void String::append(const std::string& str) +{ + _string.append(str); +} + +void String::appendWithFormat(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + + char* pBuf = (char*)malloc(kMaxStringLen); + if (pBuf != NULL) + { + vsnprintf(pBuf, kMaxStringLen, format, ap); + _string.append(pBuf); + free(pBuf); + } + + va_end(ap); + +} + +Array* String::componentsSeparatedByString(const char *delimiter) +{ + Array* result = Array::create(); + + int cutAt; + while( (cutAt = _string.find_first_of(delimiter)) != _string.npos ) + { + if(cutAt > 0) + { + result->addObject(String::create(_string.substr(0, cutAt))); + } + _string = _string.substr(cutAt + 1); + } + + if(_string.length() > 0) + { + result->addObject(String::create(_string)); + } + + return result; +} + +bool String::isEqual(const Object* pObject) +{ + bool bRet = false; + const String* pStr = dynamic_cast(pObject); + if (pStr != NULL) + { + if (0 == _string.compare(pStr->_string)) + { + bRet = true; + } + } + return bRet; +} + +String* String::create(const std::string& str) +{ + String* pRet = new String(str); + pRet->autorelease(); + return pRet; +} + +String* String::createWithData(const unsigned char* pData, unsigned long nLen) +{ + String* pRet = NULL; + if (pData != NULL) + { + char* pStr = (char*)malloc(nLen+1); + if (pStr != NULL) + { + pStr[nLen] = '\0'; + if (nLen > 0) + { + memcpy(pStr, pData, nLen); + } + + pRet = String::create(pStr); + free(pStr); + } + } + return pRet; +} + +String* String::createWithFormat(const char* format, ...) +{ + String* pRet = String::create(""); + va_list ap; + va_start(ap, format); + pRet->initWithFormatAndValist(format, ap); + va_end(ap); + + return pRet; +} + +String* String::createWithContentsOfFile(const char* filename) +{ + unsigned long size = 0; + unsigned char* pData = 0; + String* pRet = NULL; + pData = FileUtils::getInstance()->getFileData(filename, "rb", &size); + pRet = String::createWithData(pData, size); + CC_SAFE_DELETE_ARRAY(pData); + return pRet; +} + +void String::acceptVisitor(DataVisitor &visitor) +{ + visitor.visit(this); +} + +String* String::clone() const +{ + return String::create(_string); +} + +NS_CC_END diff --git a/cocos/base/cocoa/CCString.h b/cocos/base/cocoa/CCString.h new file mode 100644 index 0000000000..a6f237a476 --- /dev/null +++ b/cocos/base/cocoa/CCString.h @@ -0,0 +1,210 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ +#ifndef __CCSTRING_H__ +#define __CCSTRING_H__ + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY) +#include +#endif + +#include +#include +#include +#include "CCObject.h" + +NS_CC_BEGIN + +/** + * @addtogroup data_structures + * @{ + */ + +class CC_DLL String : public Object, public Clonable +{ +public: + /** + * @js NA + * @lua NA + */ + String(); + /** + * @js NA + * @lua NA + */ + String(const char* str); + /** + * @js NA + * @lua NA + */ + String(const std::string& str); + /** + * @js NA + * @lua NA + */ + String(const String& str); + /** + * @js NA + * @lua NA + */ + virtual ~String(); + + /* override assignment operator + * @js NA + * @lua NA + */ + String& operator= (const String& other); + + /** init a string with format, it's similar with the c function 'sprintf' + * @js NA + * @lua NA + */ + bool initWithFormat(const char* format, ...) CC_FORMAT_PRINTF(2, 3); + + /** convert to int value + * @js NA + */ + int intValue() const; + + /** convert to unsigned int value + * @js NA + */ + unsigned int uintValue() const; + + /** convert to float value + * @js NA + */ + float floatValue() const; + + /** convert to double value + * @js NA + */ + double doubleValue() const; + + /** convert to bool value + * @js NA + */ + bool boolValue() const; + + /** get the C string + * @js NA + */ + const char* getCString() const; + + /** get the length of string + * @js NA + */ + unsigned int length() const; + + /** compare to a c string + * @js NA + */ + int compare(const char *) const; + + /** append additional characters at the end of its current value + * @js NA + * @lua NA + */ + void append(const std::string& str); + + /** append(w/ format) additional characters at the end of its current value + * @js NA + * @lua NA + */ + void appendWithFormat(const char* format, ...); + + /** split a string + * @js NA + * @lua NA + */ + Array* componentsSeparatedByString(const char *delimiter); + + /* override functions + * @js NA + */ + virtual bool isEqual(const Object* pObject); + + /** create a string with std string, you can also pass a c string pointer because the default constructor of std::string can access a c string pointer. + * @return A String pointer which is an autorelease object pointer, + * it means that you needn't do a release operation unless you retain it. + * @js NA + */ + static String* create(const std::string& str); + + /** create a string with format, it's similar with the c function 'sprintf', the default buffer size is (1024*100) bytes, + * if you want to change it, you should modify the kMaxStringLen macro in String.cpp file. + * @return A String pointer which is an autorelease object pointer, + * it means that you needn't do a release operation unless you retain it. + * @js NA + */ + static String* createWithFormat(const char* format, ...) CC_FORMAT_PRINTF(1, 2); + + /** create a string with binary data + * @return A String pointer which is an autorelease object pointer, + * it means that you needn't do a release operation unless you retain it. + * @js NA + */ + static String* createWithData(const unsigned char* pData, unsigned long nLen); + + /** create a string with a file, + * @return A String pointer which is an autorelease object pointer, + * it means that you needn't do a release operation unless you retain it. + * @js NA + */ + static String* createWithContentsOfFile(const char* filename); + /** + * @js NA + * @lua NA + */ + virtual void acceptVisitor(DataVisitor &visitor); + /** + * @js NA + * @lua NA + */ + virtual String* clone() const; + +private: + + /** only for internal use */ + bool initWithFormatAndValist(const char* format, va_list ap); + +public: + std::string _string; +}; + +struct StringCompare : public std::binary_function { + public: + bool operator() (String * a, String * b) const { + return strcmp(a->getCString(), b->getCString()) < 0; + } +}; + +#define StringMake(str) String::create(str) +#define ccs StringMake + +// end of data_structure group +/// @} + +NS_CC_END + +#endif //__CCSTRING_H__ diff --git a/cocos/base/etc1/etc1.cpp b/cocos/base/etc1/etc1.cpp new file mode 100644 index 0000000000..9c1cd43e83 --- /dev/null +++ b/cocos/base/etc1/etc1.cpp @@ -0,0 +1,670 @@ +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "etc1.h" + +#include + +/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt + + The number of bits that represent a 4x4 texel block is 64 bits if + is given by ETC1_RGB8_OES. + + The data for a block is a number of bytes, + + {q0, q1, q2, q3, q4, q5, q6, q7} + + where byte q0 is located at the lowest memory address and q7 at + the highest. The 64 bits specifying the block is then represented + by the following 64 bit integer: + + int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; + + ETC1_RGB8_OES: + + a) bit layout in bits 63 through 32 if diffbit = 0 + + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 + ----------------------------------------------- + | base col1 | base col2 | base col1 | base col2 | + | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| + ----------------------------------------------- + + 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + --------------------------------------------------- + | base col1 | base col2 | table | table |diff|flip| + | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | + --------------------------------------------------- + + + b) bit layout in bits 63 through 32 if diffbit = 1 + + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 + ----------------------------------------------- + | base col1 | dcol 2 | base col1 | dcol 2 | + | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | + ----------------------------------------------- + + 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + --------------------------------------------------- + | base col 1 | dcol 2 | table | table |diff|flip| + | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | + --------------------------------------------------- + + + c) bit layout in bits 31 through 0 (in both cases) + + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + ----------------------------------------------- + | most significant pixel index bits | + | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| + ----------------------------------------------- + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + -------------------------------------------------- + | least significant pixel index bits | + | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | + -------------------------------------------------- + + + Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: + + table codeword modifier table + ------------------ ---------------------- + 0 -8 -2 2 8 + 1 -17 -5 5 17 + 2 -29 -9 9 29 + 3 -42 -13 13 42 + 4 -60 -18 18 60 + 5 -80 -24 24 80 + 6 -106 -33 33 106 + 7 -183 -47 47 183 + + + Add table 3.17.3 Mapping from pixel index values to modifier values for + ETC1 compressed textures: + + pixel index value + --------------- + msb lsb resulting modifier value + ----- ----- ------------------------- + 1 1 -b (large negative value) + 1 0 -a (small negative value) + 0 0 a (small positive value) + 0 1 b (large positive value) + + + */ + +static const int kModifierTable[] = { +/* 0 */2, 8, -2, -8, +/* 1 */5, 17, -5, -17, +/* 2 */9, 29, -9, -29, +/* 3 */13, 42, -13, -42, +/* 4 */18, 60, -18, -60, +/* 5 */24, 80, -24, -80, +/* 6 */33, 106, -33, -106, +/* 7 */47, 183, -47, -183 }; + +static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; + +static inline etc1_byte clamp(int x) { + return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); +} + +static +inline int convert4To8(int b) { + int c = b & 0xf; + return (c << 4) | c; +} + +static +inline int convert5To8(int b) { + int c = b & 0x1f; + return (c << 3) | (c >> 2); +} + +static +inline int convert6To8(int b) { + int c = b & 0x3f; + return (c << 2) | (c >> 4); +} + +static +inline int divideBy255(int d) { + return (d + 128 + (d >> 8)) >> 8; +} + +static +inline int convert8To4(int b) { + int c = b & 0xff; + return divideBy255(c * 15); +} + +static +inline int convert8To5(int b) { + int c = b & 0xff; + return divideBy255(c * 31); +} + +static +inline int convertDiff(int base, int diff) { + return convert5To8((0x1f & base) + kLookup[0x7 & diff]); +} + +static +void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, + etc1_uint32 low, bool second, bool flipped) { + int baseX = 0; + int baseY = 0; + if (second) { + if (flipped) { + baseY = 2; + } else { + baseX = 2; + } + } + for (int i = 0; i < 8; i++) { + int x, y; + if (flipped) { + x = baseX + (i >> 1); + y = baseY + (i & 1); + } else { + x = baseX + (i >> 2); + y = baseY + (i & 3); + } + int k = y + (x * 4); + int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); + int delta = table[offset]; + etc1_byte* q = pOut + 3 * (x + 4 * y); + *q++ = clamp(r + delta); + *q++ = clamp(g + delta); + *q++ = clamp(b + delta); + } +} + +// Input is an ETC1 compressed version of the data. +// Output is a 4 x 4 square of 3-byte pixels in form R, G, B + +void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { + etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; + etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; + int r1, r2, g1, g2, b1, b2; + if (high & 2) { + // differential + int rBase = high >> 27; + int gBase = high >> 19; + int bBase = high >> 11; + r1 = convert5To8(rBase); + r2 = convertDiff(rBase, high >> 24); + g1 = convert5To8(gBase); + g2 = convertDiff(gBase, high >> 16); + b1 = convert5To8(bBase); + b2 = convertDiff(bBase, high >> 8); + } else { + // not differential + r1 = convert4To8(high >> 28); + r2 = convert4To8(high >> 24); + g1 = convert4To8(high >> 20); + g2 = convert4To8(high >> 16); + b1 = convert4To8(high >> 12); + b2 = convert4To8(high >> 8); + } + int tableIndexA = 7 & (high >> 5); + int tableIndexB = 7 & (high >> 2); + const int* tableA = kModifierTable + tableIndexA * 4; + const int* tableB = kModifierTable + tableIndexB * 4; + bool flipped = (high & 1) != 0; + decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); + decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); +} + +typedef struct { + etc1_uint32 high; + etc1_uint32 low; + etc1_uint32 score; // Lower is more accurate +} etc_compressed; + +static +inline void take_best(etc_compressed* a, const etc_compressed* b) { + if (a->score > b->score) { + *a = *b; + } +} + +static +void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, + etc1_byte* pColors, bool flipped, bool second) { + int r = 0; + int g = 0; + int b = 0; + + if (flipped) { + int by = 0; + if (second) { + by = 2; + } + for (int y = 0; y < 2; y++) { + int yy = by + y; + for (int x = 0; x < 4; x++) { + int i = x + 4 * yy; + if (inMask & (1 << i)) { + const etc1_byte* p = pIn + i * 3; + r += *(p++); + g += *(p++); + b += *(p++); + } + } + } + } else { + int bx = 0; + if (second) { + bx = 2; + } + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 2; x++) { + int xx = bx + x; + int i = xx + 4 * y; + if (inMask & (1 << i)) { + const etc1_byte* p = pIn + i * 3; + r += *(p++); + g += *(p++); + b += *(p++); + } + } + } + } + pColors[0] = (etc1_byte)((r + 4) >> 3); + pColors[1] = (etc1_byte)((g + 4) >> 3); + pColors[2] = (etc1_byte)((b + 4) >> 3); +} + +static +inline int square(int x) { + return x * x; +} + +static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, + const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, + const int* pModifierTable) { + etc1_uint32 bestScore = ~0; + int bestIndex = 0; + int pixelR = pIn[0]; + int pixelG = pIn[1]; + int pixelB = pIn[2]; + int r = pBaseColors[0]; + int g = pBaseColors[1]; + int b = pBaseColors[2]; + for (int i = 0; i < 4; i++) { + int modifier = pModifierTable[i]; + int decodedG = clamp(g + modifier); + etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); + if (score >= bestScore) { + continue; + } + int decodedR = clamp(r + modifier); + score += (etc1_uint32) (3 * square(decodedR - pixelR)); + if (score >= bestScore) { + continue; + } + int decodedB = clamp(b + modifier); + score += (etc1_uint32) square(decodedB - pixelB); + if (score < bestScore) { + bestScore = score; + bestIndex = i; + } + } + etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) + << bitIndex; + *pLow |= lowMask; + return bestScore; +} + +static +void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, + etc_compressed* pCompressed, bool flipped, bool second, + const etc1_byte* pBaseColors, const int* pModifierTable) { + int score = pCompressed->score; + if (flipped) { + int by = 0; + if (second) { + by = 2; + } + for (int y = 0; y < 2; y++) { + int yy = by + y; + for (int x = 0; x < 4; x++) { + int i = x + 4 * yy; + if (inMask & (1 << i)) { + score += chooseModifier(pBaseColors, pIn + i * 3, + &pCompressed->low, yy + x * 4, pModifierTable); + } + } + } + } else { + int bx = 0; + if (second) { + bx = 2; + } + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 2; x++) { + int xx = bx + x; + int i = xx + 4 * y; + if (inMask & (1 << i)) { + score += chooseModifier(pBaseColors, pIn + i * 3, + &pCompressed->low, y + xx * 4, pModifierTable); + } + } + } + } + pCompressed->score = score; +} + +static bool inRange4bitSigned(int color) { + return color >= -4 && color <= 3; +} + +static void etc_encodeBaseColors(etc1_byte* pBaseColors, + const etc1_byte* pColors, etc_compressed* pCompressed) { + int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks + bool differential; + { + int r51 = convert8To5(pColors[0]); + int g51 = convert8To5(pColors[1]); + int b51 = convert8To5(pColors[2]); + int r52 = convert8To5(pColors[3]); + int g52 = convert8To5(pColors[4]); + int b52 = convert8To5(pColors[5]); + + r1 = convert5To8(r51); + g1 = convert5To8(g51); + b1 = convert5To8(b51); + + int dr = r52 - r51; + int dg = g52 - g51; + int db = b52 - b51; + + differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) + && inRange4bitSigned(db); + if (differential) { + r2 = convert5To8(r51 + dr); + g2 = convert5To8(g51 + dg); + b2 = convert5To8(b51 + db); + pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) + | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; + } + } + + if (!differential) { + int r41 = convert8To4(pColors[0]); + int g41 = convert8To4(pColors[1]); + int b41 = convert8To4(pColors[2]); + int r42 = convert8To4(pColors[3]); + int g42 = convert8To4(pColors[4]); + int b42 = convert8To4(pColors[5]); + r1 = convert4To8(r41); + g1 = convert4To8(g41); + b1 = convert4To8(b41); + r2 = convert4To8(r42); + g2 = convert4To8(g42); + b2 = convert4To8(b42); + pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 + << 16) | (b41 << 12) | (b42 << 8); + } + pBaseColors[0] = r1; + pBaseColors[1] = g1; + pBaseColors[2] = b1; + pBaseColors[3] = r2; + pBaseColors[4] = g2; + pBaseColors[5] = b2; +} + +static +void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, + const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { + pCompressed->score = ~0; + pCompressed->high = (flipped ? 1 : 0); + pCompressed->low = 0; + + etc1_byte pBaseColors[6]; + + etc_encodeBaseColors(pBaseColors, pColors, pCompressed); + + int originalHigh = pCompressed->high; + + const int* pModifierTable = kModifierTable; + for (int i = 0; i < 8; i++, pModifierTable += 4) { + etc_compressed temp; + temp.score = 0; + temp.high = originalHigh | (i << 5); + temp.low = 0; + etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, + pBaseColors, pModifierTable); + take_best(pCompressed, &temp); + } + pModifierTable = kModifierTable; + etc_compressed firstHalf = *pCompressed; + for (int i = 0; i < 8; i++, pModifierTable += 4) { + etc_compressed temp; + temp.score = firstHalf.score; + temp.high = firstHalf.high | (i << 2); + temp.low = firstHalf.low; + etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, + pBaseColors + 3, pModifierTable); + if (i == 0) { + *pCompressed = temp; + } else { + take_best(pCompressed, &temp); + } + } +} + +static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { + pOut[0] = (etc1_byte)(d >> 24); + pOut[1] = (etc1_byte)(d >> 16); + pOut[2] = (etc1_byte)(d >> 8); + pOut[3] = (etc1_byte) d; +} + +// Input is a 4 x 4 square of 3-byte pixels in form R, G, B +// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) +// pixel is valid or not. Invalid pixel color values are ignored when compressing. +// Output is an ETC1 compressed version of the data. + +void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, + etc1_byte* pOut) { + etc1_byte colors[6]; + etc1_byte flippedColors[6]; + etc_average_colors_subblock(pIn, inMask, colors, false, false); + etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); + etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); + etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); + + etc_compressed a, b; + etc_encode_block_helper(pIn, inMask, colors, &a, false); + etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); + take_best(&a, &b); + writeBigEndian(pOut, a.high); + writeBigEndian(pOut + 4, a.low); +} + +// Return the size of the encoded image data (does not include size of PKM header). + +etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { + return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; +} + +// Encode an entire image. +// pIn - pointer to the image data. Formatted such that the Red component of +// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; +// pOut - pointer to encoded data. Must be large enough to store entire encoded image. + +int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { + if (pixelSize < 2 || pixelSize > 3) { + return -1; + } + static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; + static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, + 0xffff }; + etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; + etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; + + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + + for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { + etc1_uint32 yEnd = height - y; + if (yEnd > 4) { + yEnd = 4; + } + int ymask = kYMask[yEnd]; + for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { + etc1_uint32 xEnd = width - x; + if (xEnd > 4) { + xEnd = 4; + } + int mask = ymask & kXMask[xEnd]; + for (etc1_uint32 cy = 0; cy < yEnd; cy++) { + etc1_byte* q = block + (cy * 4) * 3; + const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); + if (pixelSize == 3) { + memcpy(q, p, xEnd * 3); + } else { + for (etc1_uint32 cx = 0; cx < xEnd; cx++) { + int pixel = (p[1] << 8) | p[0]; + *q++ = convert5To8(pixel >> 11); + *q++ = convert6To8(pixel >> 5); + *q++ = convert5To8(pixel); + p += pixelSize; + } + } + } + etc1_encode_block(block, mask, encoded); + memcpy(pOut, encoded, sizeof(encoded)); + pOut += sizeof(encoded); + } + } + return 0; +} + +// Decode an entire image. +// pIn - pointer to encoded data. +// pOut - pointer to the image data. Will be written such that the Red component of +// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be +// large enough to store entire image. + + +int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, + etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride) { + if (pixelSize < 2 || pixelSize > 3) { + return -1; + } + etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; + + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + + for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { + etc1_uint32 yEnd = height - y; + if (yEnd > 4) { + yEnd = 4; + } + for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { + etc1_uint32 xEnd = width - x; + if (xEnd > 4) { + xEnd = 4; + } + etc1_decode_block(pIn, block); + pIn += ETC1_ENCODED_BLOCK_SIZE; + for (etc1_uint32 cy = 0; cy < yEnd; cy++) { + const etc1_byte* q = block + (cy * 4) * 3; + etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); + if (pixelSize == 3) { + memcpy(p, q, xEnd * 3); + } else { + for (etc1_uint32 cx = 0; cx < xEnd; cx++) { + etc1_byte r = *q++; + etc1_byte g = *q++; + etc1_byte b = *q++; + etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); + *p++ = (etc1_byte) pixel; + *p++ = (etc1_byte) (pixel >> 8); + } + } + } + } + } + return 0; +} + +static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; + +static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; +static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; +static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; +static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; +static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; + +static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; + +static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { + pOut[0] = (etc1_byte) (data >> 8); + pOut[1] = (etc1_byte) data; +} + +static etc1_uint32 readBEUint16(const etc1_byte* pIn) { + return (pIn[0] << 8) | pIn[1]; +} + +// Format a PKM header + +void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { + memcpy(pHeader, kMagic, sizeof(kMagic)); + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); + writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); + writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); + writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); + writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); +} + +// Check if a PKM header is correctly formatted. + +etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { + if (memcmp(pHeader, kMagic, sizeof(kMagic))) { + return false; + } + etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); + etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); + etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); + etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); + etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); + return format == ETC1_RGB_NO_MIPMAPS && + encodedWidth >= width && encodedWidth - width < 4 && + encodedHeight >= height && encodedHeight - height < 4; +} + +// Read the image width from a PKM header + +etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { + return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); +} + +// Read the image height from a PKM header + +etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ + return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); +} diff --git a/cocos/base/etc1/etc1.h b/cocos/base/etc1/etc1.h new file mode 100644 index 0000000000..0d389052b7 --- /dev/null +++ b/cocos/base/etc1/etc1.h @@ -0,0 +1,106 @@ +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __etc1_h__ +#define __etc1_h__ + +#define ETC1_ENCODED_BLOCK_SIZE 8 +#define ETC1_DECODED_BLOCK_SIZE 48 + +#ifndef ETC1_RGB8_OES +#define ETC1_RGB8_OES 0x8D64 +#endif + +typedef unsigned char etc1_byte; +typedef int etc1_bool; +typedef unsigned int etc1_uint32; + +#ifdef __cplusplus +extern "C" { +#endif + +// Encode a block of pixels. +// +// pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a +// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R +// value of pixel (x, y). +// +// validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether +// the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing. +// +// pOut is an ETC1 compressed version of the data. + +void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut); + +// Decode a block of pixels. +// +// pIn is an ETC1 compressed version of the data. +// +// pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a +// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R +// value of pixel (x, y). + +void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut); + +// Return the size of the encoded image data (does not include size of PKM header). + +etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height); + +// Encode an entire image. +// pIn - pointer to the image data. Formatted such that +// pixel (x,y) is at pIn + pixelSize * x + stride * y; +// pOut - pointer to encoded data. Must be large enough to store entire encoded image. +// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. +// returns non-zero if there is an error. + +int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut); + +// Decode an entire image. +// pIn - pointer to encoded data. +// pOut - pointer to the image data. Will be written such that +// pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be +// large enough to store entire image. +// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. +// returns non-zero if there is an error. + +int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, + etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride); + +// Size of a PKM header, in bytes. + +#define ETC_PKM_HEADER_SIZE 16 + +// Format a PKM header + +void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height); + +// Check if a PKM header is correctly formatted. + +etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader); + +// Read the image width from a PKM header + +etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader); + +// Read the image height from a PKM header + +etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cocos/base/s3tc/s3tc.cpp b/cocos/base/s3tc/s3tc.cpp new file mode 100644 index 0000000000..e7869df631 --- /dev/null +++ b/cocos/base/s3tc/s3tc.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "s3tc.h" + +//Decode S3TC encode block to 4x4 RGB32 pixels +static void s3tc_decode_block(uint8_t **blockData, + uint32_t *decodeBlockData, + unsigned int stride, + bool oneBitAlphaFlag, + uint64_t alpha, + S3TCDecodeFlag decodeFlag) +{ + unsigned int colorValue0 = 0 , colorValue1 = 0, initAlpha = (!oneBitAlphaFlag * 255u) << 24; + unsigned int rb0 = 0, rb1 = 0, rb2 = 0, rb3 = 0, g0 = 0, g1 = 0, g2 = 0, g3 = 0; + + uint32_t colors[4], pixelsIndex = 0; + + /* load the two color values*/ + memcpy((void *)&colorValue0, *blockData, 2); + (*blockData) += 2; + + memcpy((void *)&colorValue1, *blockData, 2); + (*blockData) += 2; + + /* the channel is r5g6b5 , 16 bits */ + rb0 = (colorValue0 << 19 | colorValue0 >> 8) & 0xf800f8; + rb1 = (colorValue1 << 19 | colorValue1 >> 8) & 0xf800f8; + g0 = (colorValue0 << 5) & 0x00fc00; + g1 = (colorValue1 << 5) & 0x00fc00; + g0 += (g0 >> 6) & 0x000300; + g1 += (g1 >> 6) & 0x000300; + + colors[0] = rb0 + g0 + initAlpha; + colors[1] = rb1 + g1 + initAlpha; + + /* interpolate the other two color values */ + if (colorValue0 > colorValue1 || oneBitAlphaFlag) + { + rb2 = (((2*rb0 + rb1) * 21) >> 6) & 0xff00ff; + rb3 = (((2*rb1 + rb0) * 21) >> 6) & 0xff00ff; + g2 = (((2*g0 + g1 ) * 21) >> 6) & 0x00ff00; + g3 = (((2*g1 + g0 ) * 21) >> 6) & 0x00ff00; + colors[3] = rb3 + g3 + initAlpha; + } + else + { + rb2 = ((rb0+rb1) >> 1) & 0xff00ff; + g2 = ((g0 +g1 ) >> 1) & 0x00ff00; + colors[3] = 0 ; + } + colors[2] = rb2 + g2 + initAlpha; + + /*read the pixelsIndex , 2bits per pixel, 4 bytes */ + memcpy((void*)&pixelsIndex, *blockData, 4); + (*blockData) += 4; + + if (S3TCDecodeFlag::DXT5 == decodeFlag) + { + //dxt5 use interpolate alpha + // 8-Alpha block: derive the other six alphas. + // Bit code 000 = alpha0, 001 = alpha1, other are interpolated. + + unsigned int alphaArray[8]; + + alphaArray[0] = (alpha ) & 0xff ; + alphaArray[1] = (alpha >> 8) & 0xff ; + + if (alphaArray[0] >= alphaArray[1]) + { + alphaArray[2] = (alphaArray[0]*6 + alphaArray[1]*1) / 7; + alphaArray[3] = (alphaArray[0]*5 + alphaArray[1]*2) / 7; + alphaArray[4] = (alphaArray[0]*4 + alphaArray[1]*3) / 7; + alphaArray[5] = (alphaArray[0]*3 + alphaArray[1]*4) / 7; + alphaArray[6] = (alphaArray[0]*2 + alphaArray[1]*5) / 7; + alphaArray[7] = (alphaArray[0]*1 + alphaArray[1]*6) / 7; + } + else if (alphaArray[0] < alphaArray[1]) + { + alphaArray[2] = (alphaArray[0]*4 + alphaArray[1]*1) / 5; + alphaArray[3] = (alphaArray[0]*3 + alphaArray[1]*2) / 5; + alphaArray[4] = (alphaArray[0]*2 + alphaArray[1]*3) / 5; + alphaArray[5] = (alphaArray[0]*1 + alphaArray[1]*4) / 5; + alphaArray[6] = 0; + alphaArray[7] = 255; + } + + // read the flowing 48bit indices (16*3) + alpha >>= 16; + + for (int y = 0; y < 4; ++y) + { + for (int x = 0; x < 4; ++x) + { + decodeBlockData[x] = (alphaArray[alpha & 5] << 24) + colors[pixelsIndex & 3]; + pixelsIndex >>= 2; + alpha >>= 3; + } + decodeBlockData += stride; + } + } //if (dxt5 == comFlag) + else + { //dxt1 dxt3 use explicit alpha + for (int y = 0; y < 4; ++y) + { + for (int x = 0; x < 4; ++x) + { + initAlpha = (alpha & 0x0f) << 28; + initAlpha += initAlpha >> 4; + decodeBlockData[x] = initAlpha + colors[pixelsIndex & 3]; + pixelsIndex >>= 2; + alpha >>= 4; + } + decodeBlockData += stride; + } + } +} + +//Decode S3TC encode data to RGB32 +void s3tc_decode(uint8_t *encodeData, //in_data + uint8_t *decodeData, //out_data + const int pixelsWidth, + const int pixelsHeight, + S3TCDecodeFlag decodeFlag) +{ + uint32_t *decodeBlockData = (uint32_t *)decodeData; + for (int block_y = 0; block_y < pixelsHeight / 4; ++block_y, decodeBlockData += 3 * pixelsWidth) //stride = 3*width + { + for(int block_x = 0; block_x < pixelsWidth / 4; ++block_x, decodeBlockData += 4) //skip 4 pixels + { + uint64_t blockAlpha = 0; + + switch (decodeFlag) + { + case S3TCDecodeFlag::DXT1: + { + s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 0, 0LL, S3TCDecodeFlag::DXT1); + } + break; + case S3TCDecodeFlag::DXT3: + { + memcpy((void *)&blockAlpha, encodeData, 8); + encodeData += 8; + s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, S3TCDecodeFlag::DXT3); + } + break; + case S3TCDecodeFlag::DXT5: + { + memcpy((void *)&blockAlpha, encodeData, 8); + encodeData += 8; + s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, S3TCDecodeFlag::DXT5); + } + break; + default: + break; + }//switch + }//for block_x + }//for block_y +} + + diff --git a/cocos/base/s3tc/s3tc.h b/cocos/base/s3tc/s3tc.h new file mode 100644 index 0000000000..a3cf233257 --- /dev/null +++ b/cocos/base/s3tc/s3tc.h @@ -0,0 +1,48 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + + +#ifndef COCOS2DX_PLATFORM_THIRDPARTY_S3TC_ +#define COCOS2DX_PLATFORM_THIRDPARTY_S3TC_ + +#include "CCStdC.h" + +enum class S3TCDecodeFlag +{ + DXT1 = 1, + DXT3 = 3, + DXT5 = 5, +}; + +//Decode S3TC encode data to RGB32 + void s3tc_decode(uint8_t *encode_data, + uint8_t *decode_data, + const int pixelsWidth, + const int pixelsHeight, + S3TCDecodeFlag decodeFlag + ); + + +#endif /* defined(COCOS2DX_PLATFORM_THIRDPARTY_S3TC_) */ + diff --git a/external/tinyxml2/tinyxml2.cpp b/external/tinyxml2/tinyxml2.cpp new file mode 100644 index 0000000000..f181b9050c --- /dev/null +++ b/external/tinyxml2/tinyxml2.cpp @@ -0,0 +1,2101 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +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 "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +# if defined(ANDROID_NDK) || (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY) +# include +#else +# include +#endif + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + +#define DELETE_NODE( node ) { \ + if ( node ) { \ + MemPool* pool = node->_memPool; \ + node->~XMLNode(); \ + pool->Free( node ); \ + } \ + } +#define DELETE_ATTRIBUTE( attrib ) { \ + if ( attrib ) { \ + MemPool* pool = attrib->_memPool; \ + attrib->~XMLAttribute(); \ + pool->Free( attrib ); \ + } \ + } + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + Reset(); + size_t len = strlen( str ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) +{ + TIXMLASSERT( endTag && *endTag ); + + char* start = p; // fixme: hides a member + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } + ++p; + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + char* start = p; + + if ( !start || !(*start) ) { + return 0; + } + + while( *p && ( + XMLUtil::IsAlphaNum( (unsigned char) *p ) + || *p == '_' + || *p == ':' + || (*p == '-' && p>start ) // can be in a name, but not lead it. + || (*p == '.' && p>start ) )) { // can be in a name, but not lead it. + ++p; + } + + if ( p > start ) { + Set( start, p, 0 ); + return p; + } + return 0; +} + + +void StrPair::CollapseWhitespace() +{ + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start ); + + if ( _start && *_start ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + char buf[10] = { 0 }; + int len; + p = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + for( int i=0; i(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't covert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs. + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + default: + break; + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + if ( !*(p+3) ) { + return 0; + } + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) { + return 0; + } + + delta = q-p; + --q; + + while ( *q != 'x' ) { + if ( *q >= '0' && *q <= '9' ) { + ucs += mult * (*q - '0'); + } + else if ( *q >= 'a' && *q <= 'f' ) { + ucs += mult * (*q - 'a' + 10); + } + else if ( *q >= 'A' && *q <= 'F' ) { + ucs += mult * (*q - 'A' + 10 ); + } + else { + return 0; + } + mult *= 16; + --q; + } + } + else { + // Decimal. + if ( !*(p+2) ) { + return 0; + } + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) { + return 0; + } + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + ucs += mult * (*q - '0'); + } + else { + return 0; + } + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); +} + + +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%g", v ); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + XMLNode* returnNode = 0; + char* start = p; + p = XMLUtil::SkipWhiteSpace( p ); + if( !p || !*p ) { + return p; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + if ( p == 0 || node == 0 ) { + break; + } + + StrPair endTag; + p = node->ParseDeep( p, &endTag ); + if ( !p ) { + DELETE_NODE( node ); + node = 0; + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, 0, 0 ); + } + break; + } + + // We read the end tag. Return it to the parent. + if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) { + if ( parentEnd ) { + *parentEnd = static_cast(node)->_value; + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DELETE_NODE( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + XMLElement* ele = node->ToElement(); + if ( ele ) { + if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); + p = 0; + } + else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); + p = 0; + } + else if ( !endTag.Empty() ) { + if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); + p = 0; + } + } + } + if ( p == 0 ) { + DELETE_NODE( node ); + node = 0; + } + if ( node ) { + this->InsertEndChild( node ); + } + } + return 0; +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair* ) +{ + const char* start = p; + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::COLLAPSE_WHITESPACE; + } + + p = _value.ParseText( p, "<", flags ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + } + if ( p && *p ) { + return p-1; + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() )); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair* ) +{ + // Comment parses as text. + const char* start = p; + p = _value.ParseText( p, "-->", StrPair::COMMENT ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) +{ + // Declaration parses as text. + const char* start = p; + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair* ) +{ + // Unknown parses as text. + const char* start = p; + + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p ); + if ( !p || *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( 0 ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DELETE_ATTRIBUTE( _rootAttribute ); + _rootAttribute = next; + } +} + + +XMLAttribute* XMLElement::FindAttribute( const char* name ) +{ + XMLAttribute* a = 0; + for( a=_rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + XMLAttribute* a = 0; + for( a=_rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->ToText()->Value(); + } + return 0; +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->ToText()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->ToText()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->ToText()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->ToText()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->ToText()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + if ( last ) { + last->_next = attrib; + } + else { + _rootAttribute = attrib; + } + attrib->SetName( name ); + attrib->_memPool->SetTracked(); // always created and linked. + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DELETE_ATTRIBUTE( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p ) +{ + const char* start = p; + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( !p || !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); + return 0; + } + + // attribute. + if ( XMLUtil::IsAlpha( *p ) ) { + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + + p = attrib->ParseDeep( p, _document->ProcessEntities() ); + if ( !p || Attribute( attrib->Name() ) ) { + DELETE_ATTRIBUTE( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + prevAttribute->_next = attrib; + } + else { + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); + return 0; + } + } + return p; +} + + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p ); + if ( !p ) { + return 0; + } + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p ); + if ( !p || !*p || _closingType ) { + return p; + } + + p = XMLNode::ParseDeep( p, strPair ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID( XML_NO_ERROR ), + _whitespace( whitespace ), + _errorStr1( 0 ), + _errorStr2( 0 ), + _charBuffer( 0 ) +{ + _document = this; // avoid warning about 'this' in initializer list +} + + +XMLDocument::~XMLDocument() +{ + DeleteChildren(); + delete [] _charBuffer; + +#if 0 + textPool.Trace( "text" ); + elementPool.Trace( "element" ); + commentPool.Trace( "comment" ); + attributePool.Trace( "attribute" ); +#endif + +#ifdef DEBUG + if ( Error() == false ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +void XMLDocument::InitDocument() +{ + _errorID = XML_NO_ERROR; + _errorStr1 = 0; + _errorStr2 = 0; + + delete [] _charBuffer; + _charBuffer = 0; +} + + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); + ele->_memPool = &_elementPool; + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); + comment->_memPool = &_commentPool; + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + text->_memPool = &_textPool; + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); + dec->_memPool = &_commentPool; + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); + unk->_memPool = &_commentPool; + unk->SetValue( str ); + return unk; +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + DeleteChildren(); + InitDocument(); + FILE* fp = 0; + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + errno_t err = fopen_s(&fp, filename, "rb" ); + if ( !fp || err) { +#else + fp = fopen( filename, "rb" ); + if ( !fp) { +#endif + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + DeleteChildren(); + InitDocument(); + + fseek( fp, 0, SEEK_END ); + size_t size = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + + if ( size == 0 ) { + return _errorID; + } + + _charBuffer = new char[size+1]; + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + const char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::ReadBOM( p, &_writeBOM ); + if ( !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + ParseDeep( _charBuffer + (p-_charBuffer), 0 ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + FILE* fp = 0; +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + errno_t err = fopen_s(&fp, filename, "w" ); + if ( !fp || err) { +#else + fp = fopen( filename, "w" ); + if ( !fp) { +#endif + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + DeleteChildren(); + InitDocument(); + + if ( !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::ReadBOM( p, &_writeBOM ); + if ( !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + ParseDeep( _charBuffer, 0 ); + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) +{ + XMLPrinter stdStreamer( stdout ); + if ( !streamer ) { + streamer = &stdStreamer; + } + Accept( streamer ); +} + + +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) +{ + _errorID = error; + _errorStr1 = str1; + _errorStr2 = str2; +} + + +void XMLDocument::PrintError() const +{ + if ( _errorID ) { + static const int LEN = 20; + char buf1[LEN] = { 0 }; + char buf2[LEN] = { 0 }; + + if ( _errorStr1 ) { + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); + } + if ( _errorStr2 ) { + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); + } + + printf( "XMLDocument error id=%d str1=%s str2=%s\n", + _errorID, buf1, buf2 ); + } +} + + +XMLPrinter::XMLPrinter( FILE* file, bool compact ) : + _elementJustOpened( false ), + _firstElement( true ), + _fp( file ), + _depth( 0 ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ) +{ + for( int i=0; i'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + // This seems brutally complex. Haven't figured out a better + // way on windows. +#if defined _MSC_VER && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + int len = -1; + int expand = 1000; + while ( len < 0 ) { + len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va ); + if ( len < 0 ) { + expand *= 3/2; + _accumulator.PushArr( expand ); + } + } + char* p = _buffer.PushArr( len ) - 1; + memcpy( p, _accumulator.Mem(), len+1 ); +#else + int len = vsnprintf( 0, 0, format, va ); + // Close out and re-start the va-args + va_end( va ); + va_start( va, format ); + char* p = _buffer.PushArr( len ) - 1; + vsnprintf( p, len+1, format, va ); +#endif + } + va_end( va ); +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned)(*q)] ) { + while ( p < q ) { + Print( "%c", *p ); + ++p; + } + for( int i=0; i 0) ) { + Print( "%s", p ); + } +} + + +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) +{ + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + if ( writeBOM ) { + Print( "%s", bom ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + + +void XMLPrinter::OpenElement( const char* name ) +{ + if ( _elementJustOpened ) { + SealElement(); + } + _stack.Push( name ); + + if ( _textDepth < 0 && !_firstElement && !_compactMode ) { + Print( "\n" ); + PrintSpace( _depth ); + } + + Print( "<%s", name ); + _elementJustOpened = true; + _firstElement = false; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Print( " %s=\"", name ); + PrintString( value, false ); + Print( "\"" ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement() +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Print( "/>" ); + } + else { + if ( _textDepth < 0 && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + Print( "", name ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !_compactMode) { + Print( "\n" ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElement() +{ + _elementJustOpened = false; + Print( ">" ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + if ( _elementJustOpened ) { + SealElement(); + } + if ( cdata ) { + Print( "" ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + if ( _elementJustOpened ) { + SealElement(); + } + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", comment ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + if ( _elementJustOpened ) { + SealElement(); + } + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + if ( _elementJustOpened ) { + SealElement(); + } + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + OpenElement( element.Name() ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& ) +{ + CloseElement(); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 + diff --git a/external/tinyxml2/tinyxml2.h b/external/tinyxml2/tinyxml2.h new file mode 100644 index 0000000000..eeffa1096f --- /dev/null +++ b/external/tinyxml2/tinyxml2.h @@ -0,0 +1,1914 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +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. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#include "platform/CCPlatformConfig.h" +#include "platform/CCPlatformMacros.h" + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY) +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +#endif + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + + +#if defined(DEBUG) +# if defined(_MSC_VER) +# define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +# else +# define TIXMLASSERT( x ) {} +#endif + + +#if (defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE)) +// Microsoft visual studio, version 2005 and higher. +/*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... +);*/ +inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) +{ + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; +} +#define TIXML_SSCANF sscanf_s +#else +// GCC version 3 and higher +//#warning( "Using sn* functions." ) +#define TIXML_SNPRINTF snprintf +#define TIXML_SSCANF sscanf +#endif + +static const int TIXML2_MAJOR_VERSION = 1; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 9; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLNode; +class XMLText; +class XMLDeclaration; +class XMLUnknown; + +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class CC_DLL StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + COLLAPSE_WHITESPACE = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags ); + char* ParseName( char* in ); + +private: + void Reset(); + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + // After parsing, if *end != 0, it can be set to zero. + int _flags; + char* _start; + char* _end; +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class CC_DLL DynArray +{ +public: + DynArray< T, INIT >() { + _mem = _pool; + _allocated = INIT; + _size = 0; + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Push( T t ) { + EnsureCapacity( _size+1 ); + _mem[_size++] = t; + } + + T* PushArr( int count ) { + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + return _mem[--_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + int Size() const { + return _size; + } + + int Capacity() const { + return _allocated; + } + + const T* Mem() const { + return _mem; + } + + T* Mem() { + return _mem; + } + +private: + void EnsureCapacity( int cap ) { + if ( cap > _allocated ) { + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INIT]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class CC_DLL MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int SIZE > +class CC_DLL MemPoolT : public MemPool +{ +public: + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + // Delete the blocks. + for( int i=0; i<_blockPtrs.Size(); ++i ) { + delete _blockPtrs[i]; + } + } + + virtual int ItemSize() const { + return SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + for( int i=0; ichunk[i].next = &block->chunk[i+1]; + } + block->chunk[COUNT-1].next = 0; + _root = block->chunk; + } + void* result = _root; + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + _nAllocs++; + _nUntracked++; + return result; + } + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Chunk* chunk = (Chunk*)mem; +#ifdef DEBUG + memset( chunk, 0xfe, sizeof(Chunk) ); +#endif + chunk->next = _root; + _root = chunk; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + _nUntracked--; + } + + int Untracked() const { + return _nUntracked; + } + + enum { COUNT = 1024/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private + +private: + union Chunk { + Chunk* next; + char mem[SIZE]; + }; + struct Block { + Chunk chunk[COUNT]; + }; + DynArray< Block*, 10 > _blockPtrs; + Chunk* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class CC_DLL XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + + +/* + Utility functionality. +*/ +class CC_DLL XMLUtil +{ +public: + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static const char* SkipWhiteSpace( const char* p ) { + while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast(p) ) ) { + ++p; + } + return p; + } + static char* SkipWhiteSpace( char* p ) { + while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast(p) ) ) { + ++p; + } + return p; + } + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + int n = 0; + if ( p == q ) { + return true; + } + while( *p && *q && *p == *q && n(const_cast(this)->FirstChildElement( value )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return const_cast(const_cast(this)->LastChild() ); + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* value=0 ) const; + + XMLElement* LastChildElement( const char* value=0 ) { + return const_cast(const_cast(this)->LastChildElement(value) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an opitionally supplied name. + const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; + + XMLElement* PreviousSiblingElement( const char* value=0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( value ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an opitionally supplied name. + const XMLElement* NextSiblingElement( const char* value=0 ) const; + + XMLElement* NextSiblingElement( const char* value=0 ) { + return const_cast(const_cast(this)->NextSiblingElement( value ) ); + } + + /** + Add a child node as the last (right) child. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + // internal + virtual char* ParseDeep( char*, StrPair* ); + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class CC_DLL XMLText : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + char* ParseDeep( char*, StrPair* endTag ); + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported + +private: + bool _isCData; +}; + + +/** An XML Comment. */ +class CC_DLL XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + char* ParseDeep( char*, StrPair* endTag ); + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported + +private: +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class CC_DLL XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + char* ParseDeep( char*, StrPair* endTag ); + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class CC_DLL XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + char* ParseDeep( char*, StrPair* endTag ); + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + +enum XMLError { + XML_NO_ERROR = 0, + XML_SUCCESS = 0, + + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_ELEMENT_MISMATCH, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_IDENTIFYING_TAG, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class CC_DLL XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const { + return _name.GetStr(); + } + /// The value of the attribute. + const char* Value() const { + return _value.GetStr(); + } + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntAttribute interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntAttribute() if you need error checking. + */ + int IntValue() const { + int i=0; + QueryIntValue( &i ); + return i; + } + /// Query as an unsigned integer. See IntAttribute() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntAttribute() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntAttribute() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntAttribute() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntAttribute interprets the attribute as an integer, and returns the value + in the provided paremeter. The function will return XML_NO_ERROR on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntAttribute + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntAttribute + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntAttribute + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntAttribute + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _next( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities ); + + mutable StrPair _name; + mutable StrPair _value; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class CC_DLL XMLElement : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. 0 will be + returned if there is an error. For a method with error + checking, see QueryIntAttribute() + */ + int IntAttribute( const char* name ) const { + int i=0; + QueryIntAttribute( name, &i ); + return i; + } + /// See IntAttribute() + unsigned UnsignedAttribute( const char* name ) const { + unsigned i=0; + QueryUnsignedAttribute( name, &i ); + return i; + } + /// See IntAttribute() + bool BoolAttribute( const char* name ) const { + bool b=false; + QueryBoolAttribute( name, &b ); + return b; + } + /// See IntAttribute() + double DoubleAttribute( const char* name ) const { + double d=0; + QueryDoubleAttribute( name, &d ); + return d; + } + /// See IntAttribute() + float FloatAttribute( const char* name ) const { + float f=0; + QueryFloatAttribute( name, &f ); + return f; + } + + /** Given an attribute name, QueryIntAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + // internal: + enum { + OPEN, // + CLOSED, // + CLOSING // + }; + int ClosingType() const { + return _closingType; + } + char* ParseDeep( char* p, StrPair* endTag ); + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ); + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p ); + + int _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class CC_DLL XMLDocument : public XMLNode +{ + friend class XMLElement; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + return this; + } + virtual const XMLDocument* ToDocument() const { + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_NO_ERROR (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespace; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc->Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ); + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory forthe object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ) { + node->_parent->DeleteChild( node ); + } + + void SetError( XMLError error, const char* str1, const char* str2 ); + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_NO_ERROR; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + /// Return a possibly helpful diagnostic location or string. + const char* GetErrorStr1() const { + return _errorStr1; + } + /// Return a possibly helpful secondary diagnostic location or string. + const char* GetErrorStr2() const { + return _errorStr2; + } + /// If there is an error, print it to stdout. + void PrintError() const; + + // internal + char* Identify( char* p, XMLNode** node ); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + void InitDocument(); + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespace; + const char* _errorStr1; + const char* _errorStr2; + char* _charBuffer; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; +}; + + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class CC_DLL XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) { + _node = node; + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) { + _node = &node; + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) { + _node = ref._node; + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* value=0 ) { + return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* _value=0 ) { + return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* _value=0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* _value=0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class CC_DLL XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) { + _node = node; + } + XMLConstHandle( const XMLNode& node ) { + _node = &node; + } + XMLConstHandle( const XMLConstHandle& ref ) { + _node = ref._node; + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* value=0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* _value=0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc->Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class CC_DLL XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false ); + ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + void CloseElement(); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + +private: + void SealElement(); + void PrintSpace( int depth ); + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + void Print( const char* format, ... ); + + bool _elementJustOpened; + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< const char*, 10 > _stack; + DynArray< char, 20 > _buffer; +#ifdef _MSC_VER + DynArray< char, 20 > _accumulator; +#endif +}; + + +} // tinyxml2 + + +#endif // TINYXML2_INCLUDED diff --git a/external/unzip/ioapi.cpp b/external/unzip/ioapi.cpp new file mode 100644 index 0000000000..669ea36927 --- /dev/null +++ b/external/unzip/ioapi.cpp @@ -0,0 +1,245 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include "ioapi.h" + +namespace cocos2d { + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + { +#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE || CC_TARGET_PLATFORM == CC_PLATFORM_BADA || CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFORM_NACL || CC_TARGET_PLATFORM == CC_PLATFORM_EMSCRIPTEN) + file = NULL; +#else + file = fopen64((const char*)filename, mode_fopen); +#endif + } + + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; +#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE || CC_TARGET_PLATFORM == CC_PLATFORM_BADA || CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFORM_NACL || CC_TARGET_PLATFORM == CC_PLATFORM_EMSCRIPTEN) + ret = 0; +#else + ret = ftello64((FILE *)stream); +#endif + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ +#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE || CC_TARGET_PLATFORM == CC_PLATFORM_BADA || CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFORM_NACL || CC_TARGET_PLATFORM == CC_PLATFORM_EMSCRIPTEN) + return -1; +#else + int fseek_origin=0; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + return -1; + return 0; +#endif +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +} // end of namespace cocos2d diff --git a/external/unzip/ioapi.h b/external/unzip/ioapi.h new file mode 100644 index 0000000000..575f44ece4 --- /dev/null +++ b/external/unzip/ioapi.h @@ -0,0 +1,201 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#include "platform/CCPlatformConfig.h" + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +namespace cocos2d { + +#ifndef OF +#define OF _Z_OF +#endif + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type chosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +} // end of namespace cocos2d + +#endif diff --git a/external/unzip/unzip.cpp b/external/unzip/unzip.cpp new file mode 100644 index 0000000000..66cfeff16a --- /dev/null +++ b/external/unzip/unzip.cpp @@ -0,0 +1,2161 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +namespace cocos2d { + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialized*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structure of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structure of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been successfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is default of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spanning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spanning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easily) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) { + //lSeek=0; + } + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + //lSeek+=file_info.size_file_comment - uSizeRead; + } + //else + // lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} + +/* + Set the current file of the zipfile to the first file + with retrieving an information about the file. + return UNZ_OK if there is no problem +*/ +int ZEXPORT unzGoToFirstFile64 (unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + szFileName,fileNameBufferSize,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + if (pfile_info) + *pfile_info = s->cur_file_info; + return err; +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +int ZEXPORT unzGoToFirstFile (unzFile file) +{ + return unzGoToFirstFile64(file, NULL, NULL, 0); +} + +/* + Set the current file of the zipfile to the next file + with retrieving an information about the file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +int ZEXPORT unzGoToNextFile64 (unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + szFileName,fileNameBufferSize,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + if (pfile_info) + *pfile_info = s->cur_file_info; + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +int ZEXPORT unzGoToNextFile (unzFile file) +{ + return unzGoToNextFile64(file, NULL, NULL, 0); +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) { + + //err=UNZ_BADZIPFILE; + } + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if some bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} + +} // end of namespace cocos2d diff --git a/external/unzip/unzip.h b/external/unzip/unzip.h new file mode 100644 index 0000000000..54e73a55ea --- /dev/null +++ b/external/unzip/unzip.h @@ -0,0 +1,455 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + 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. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#include "CCPlatformDefine.h" + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +namespace cocos2d { + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +int CC_DLL unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is default of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +unzFile CC_DLL unzOpen OF((const char *path)); +unzFile CC_DLL unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +unzFile CC_DLL unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +unzFile CC_DLL unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +int CC_DLL unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +int CC_DLL unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +int CC_DLL unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +int CC_DLL unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +int CC_DLL unzGoToFirstFile OF((unzFile file)); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +int CC_DLL unzGoToFirstFile64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize)); +/* + Set the current file of the zipfile to the first file + with retrieving an information about the file. + return UNZ_OK if there is no problem +*/ + +int CC_DLL unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +int CC_DLL unzGoToNextFile64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize)); +/* + Set the current file of the zipfile to the next file + with retrieving an information about the file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +int CC_DLL unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +int CC_DLL unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +int CC_DLL unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +int CC_DLL unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +int CC_DLL unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +int CC_DLL unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +int CC_DLL unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain some info about + the current file + if szFileName!=NULL, the filename string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +ZPOS64_T CC_DLL unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +int CC_DLL unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +int CC_DLL unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +int CC_DLL unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +int CC_DLL unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +int CC_DLL unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +int CC_DLL unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if some bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +z_off_t CC_DLL unztell OF((unzFile file)); + +ZPOS64_T CC_DLL unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +int CC_DLL unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +int CC_DLL unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +ZPOS64_T CC_DLL unzGetOffset64 (unzFile file); +uLong CC_DLL unzGetOffset (unzFile file); + +/* Set the current file offset */ +int CC_DLL unzSetOffset64 (unzFile file, ZPOS64_T pos); +int CC_DLL unzSetOffset (unzFile file, uLong pos); + +} // end of namespace cocos2d + +#endif /* _unz64_H */ From bb6208eec1f339d5511cac3b4f5dc17c788e320a Mon Sep 17 00:00:00 2001 From: minggo Date: Sat, 12 Oct 2013 15:31:05 +0800 Subject: [PATCH 116/116] issue #2905: remove redundant codes --- external/atitc/atitc.cpp | 195 ------------ external/atitc/atitc.h | 48 --- external/etc1/etc1.cpp | 670 --------------------------------------- external/etc1/etc1.h | 106 ------- external/s3tc/s3tc.cpp | 182 ----------- external/s3tc/s3tc.h | 48 --- 6 files changed, 1249 deletions(-) delete mode 100644 external/atitc/atitc.cpp delete mode 100644 external/atitc/atitc.h delete mode 100644 external/etc1/etc1.cpp delete mode 100644 external/etc1/etc1.h delete mode 100644 external/s3tc/s3tc.cpp delete mode 100644 external/s3tc/s3tc.h diff --git a/external/atitc/atitc.cpp b/external/atitc/atitc.cpp deleted file mode 100644 index 3a60d6d2f7..0000000000 --- a/external/atitc/atitc.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "atitc.h" - -//Decode ATITC encode block to 4x4 RGB32 pixels -static void atitc_decode_block(uint8_t **blockData, - uint32_t *decodeBlockData, - unsigned int stride, - bool oneBitAlphaFlag, - uint64_t alpha, - ATITCDecodeFlag decodeFlag) -{ - unsigned int colorValue0 = 0 , colorValue1 = 0, initAlpha = (!oneBitAlphaFlag * 255u) << 24; - unsigned int rb0 = 0, rb1 = 0, rb2 = 0, rb3 = 0, g0 = 0, g1 = 0, g2 = 0, g3 = 0; - bool msb = 0; - - uint32_t colors[4], pixelsIndex = 0; - - /* load the two color values*/ - memcpy((void *)&colorValue0, *blockData, 2); - (*blockData) += 2; - - memcpy((void *)&colorValue1, *blockData, 2); - (*blockData) += 2; - - //extract the msb flag - msb = (colorValue0 & 0x8000) != 0; - - /* the channel is r5g6b5 , 16 bits */ - rb0 = (colorValue0 << 3 | colorValue0 << 9) & 0xf800f8; - rb1 = (colorValue1 << 3 | colorValue1 << 8) & 0xf800f8; - g0 = (colorValue0 << 6) & 0x00fc00; - g1 = (colorValue1 << 5) & 0x00fc00; - g0 += (g0 >> 6) & 0x000300; - g1 += (g1 >> 6) & 0x000300; - - /* interpolate the other two color values */ - if (!msb) - { - colors[0] = rb0 + g0 + initAlpha; - colors[3] = rb1 + g1 + initAlpha; - - rb2 = (((2*rb0 + rb1) * 21) >> 6) & 0xff00ff; - rb3 = (((2*rb1 + rb0) * 21) >> 6) & 0xff00ff; - g2 = (((2*g0 + g1 ) * 21) >> 6) & 0x00ff00; - g3 = (((2*g1 + g0 ) * 21) >> 6) & 0x00ff00; - - colors[2] = rb3 + g3 + initAlpha; - colors[1] = rb2 + g2 + initAlpha; - } - else - { - colors[2] = rb0 + g0 + initAlpha; - colors[3] = rb1 + g1 + initAlpha; - - rb2 = (rb0 - (rb1 >> 2)) & 0xff00ff; - g2 = (g0 - (g1 >> 2)) & 0x00ff00; - colors[0] = 0 ; - - colors[1] = rb2 + g2 + initAlpha; - } - - /*read the pixelsIndex , 2bits per pixel, 4 bytes */ - memcpy((void*)&pixelsIndex, *blockData, 4); - (*blockData) += 4; - - if (ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA == decodeFlag) - { - // atitc_interpolated_alpha use interpolate alpha - // 8-Alpha block: derive the other six alphas. - // Bit code 000 = alpha0, 001 = alpha1, other are interpolated. - - unsigned int alphaArray[8]; - - alphaArray[0] = (alpha ) & 0xff ; - alphaArray[1] = (alpha >> 8) & 0xff ; - - if (alphaArray[0] >= alphaArray[1]) - { - alphaArray[2] = (alphaArray[0]*6 + alphaArray[1]*1) / 7; - alphaArray[3] = (alphaArray[0]*5 + alphaArray[1]*2) / 7; - alphaArray[4] = (alphaArray[0]*4 + alphaArray[1]*3) / 7; - alphaArray[5] = (alphaArray[0]*3 + alphaArray[1]*4) / 7; - alphaArray[6] = (alphaArray[0]*2 + alphaArray[1]*5) / 7; - alphaArray[7] = (alphaArray[0]*1 + alphaArray[1]*6) / 7; - } - else if (alphaArray[0] < alphaArray[1]) - { - alphaArray[2] = (alphaArray[0]*4 + alphaArray[1]*1) / 5; - alphaArray[3] = (alphaArray[0]*3 + alphaArray[1]*2) / 5; - alphaArray[4] = (alphaArray[0]*2 + alphaArray[1]*3) / 5; - alphaArray[5] = (alphaArray[0]*1 + alphaArray[1]*4) / 5; - alphaArray[6] = 0; - alphaArray[7] = 255; - } - - // read the flowing 48bit indices (16*3) - alpha >>= 16; - - for (int y = 0; y < 4; ++y) - { - for (int x = 0; x < 4; ++x) - { - decodeBlockData[x] = (alphaArray[alpha & 5] << 24) + colors[pixelsIndex & 3]; - pixelsIndex >>= 2; - alpha >>= 3; - } - decodeBlockData += stride; - } - } //if (atc_interpolated_alpha == comFlag) - else - { - /* atc_rgb atc_explicit_alpha use explicit alpha */ - - for (int y = 0; y < 4; ++y) - { - for (int x = 0; x < 4; ++x) - { - initAlpha = (alpha & 0x0f) << 28; - initAlpha += initAlpha >> 4; - decodeBlockData[x] = initAlpha + colors[pixelsIndex & 3]; - pixelsIndex >>= 2; - alpha >>= 4; - } - decodeBlockData += stride; - } - } -} - -//Decode ATITC encode data to RGB32 -void atitc_decode(uint8_t *encodeData, //in_data - uint8_t *decodeData, //out_data - const int pixelsWidth, - const int pixelsHeight, - ATITCDecodeFlag decodeFlag) -{ - uint32_t *decodeBlockData = (uint32_t *)decodeData; - - for (int block_y = 0; block_y < pixelsHeight / 4; ++block_y, decodeBlockData += 3 * pixelsWidth) //stride = 3*width - { - for (int block_x = 0; block_x < pixelsWidth / 4; ++block_x, decodeBlockData += 4) //skip 4 pixels - { - uint64_t blockAlpha = 0; - - switch (decodeFlag) - { - case ATITCDecodeFlag::ATC_RGB: - { - atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 0, 0LL, ATITCDecodeFlag::ATC_RGB); - } - break; - case ATITCDecodeFlag::ATC_EXPLICIT_ALPHA: - { - memcpy((void *)&blockAlpha, encodeData, 8); - encodeData += 8; - atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, ATITCDecodeFlag::ATC_EXPLICIT_ALPHA); - } - break; - case ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA: - { - memcpy((void *)&blockAlpha, encodeData, 8); - encodeData += 8; - atitc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, ATITCDecodeFlag::ATC_INTERPOLATED_ALPHA); - } - break; - default: - break; - }//switch - }//for block_x - }//for block_y -} - - diff --git a/external/atitc/atitc.h b/external/atitc/atitc.h deleted file mode 100644 index 72bfd32a8c..0000000000 --- a/external/atitc/atitc.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -#ifndef COCOS2DX_PLATFORM_THIRDPARTY_ATITC_ -#define COCOS2DX_PLATFORM_THIRDPARTY_ATITC_ - -#include "CCStdC.h" - -enum class ATITCDecodeFlag -{ - ATC_RGB = 1, - ATC_EXPLICIT_ALPHA = 3, - ATC_INTERPOLATED_ALPHA = 5, -}; - -//Decode ATITC encode data to RGB32 -void atitc_decode(uint8_t *encode_data, - uint8_t *decode_data, - const int pixelsWidth, - const int pixelsHeight, - ATITCDecodeFlag decodeFlag - ); - - -#endif /* defined(COCOS2DX_PLATFORM_THIRDPARTY_ATITC_) */ - diff --git a/external/etc1/etc1.cpp b/external/etc1/etc1.cpp deleted file mode 100644 index 9c1cd43e83..0000000000 --- a/external/etc1/etc1.cpp +++ /dev/null @@ -1,670 +0,0 @@ -// Copyright 2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "etc1.h" - -#include - -/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt - - The number of bits that represent a 4x4 texel block is 64 bits if - is given by ETC1_RGB8_OES. - - The data for a block is a number of bytes, - - {q0, q1, q2, q3, q4, q5, q6, q7} - - where byte q0 is located at the lowest memory address and q7 at - the highest. The 64 bits specifying the block is then represented - by the following 64 bit integer: - - int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; - - ETC1_RGB8_OES: - - a) bit layout in bits 63 through 32 if diffbit = 0 - - 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 - ----------------------------------------------- - | base col1 | base col2 | base col1 | base col2 | - | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| - ----------------------------------------------- - - 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 - --------------------------------------------------- - | base col1 | base col2 | table | table |diff|flip| - | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | - --------------------------------------------------- - - - b) bit layout in bits 63 through 32 if diffbit = 1 - - 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 - ----------------------------------------------- - | base col1 | dcol 2 | base col1 | dcol 2 | - | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | - ----------------------------------------------- - - 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 - --------------------------------------------------- - | base col 1 | dcol 2 | table | table |diff|flip| - | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | - --------------------------------------------------- - - - c) bit layout in bits 31 through 0 (in both cases) - - 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 - ----------------------------------------------- - | most significant pixel index bits | - | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| - ----------------------------------------------- - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - -------------------------------------------------- - | least significant pixel index bits | - | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | - -------------------------------------------------- - - - Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: - - table codeword modifier table - ------------------ ---------------------- - 0 -8 -2 2 8 - 1 -17 -5 5 17 - 2 -29 -9 9 29 - 3 -42 -13 13 42 - 4 -60 -18 18 60 - 5 -80 -24 24 80 - 6 -106 -33 33 106 - 7 -183 -47 47 183 - - - Add table 3.17.3 Mapping from pixel index values to modifier values for - ETC1 compressed textures: - - pixel index value - --------------- - msb lsb resulting modifier value - ----- ----- ------------------------- - 1 1 -b (large negative value) - 1 0 -a (small negative value) - 0 0 a (small positive value) - 0 1 b (large positive value) - - - */ - -static const int kModifierTable[] = { -/* 0 */2, 8, -2, -8, -/* 1 */5, 17, -5, -17, -/* 2 */9, 29, -9, -29, -/* 3 */13, 42, -13, -42, -/* 4 */18, 60, -18, -60, -/* 5 */24, 80, -24, -80, -/* 6 */33, 106, -33, -106, -/* 7 */47, 183, -47, -183 }; - -static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; - -static inline etc1_byte clamp(int x) { - return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); -} - -static -inline int convert4To8(int b) { - int c = b & 0xf; - return (c << 4) | c; -} - -static -inline int convert5To8(int b) { - int c = b & 0x1f; - return (c << 3) | (c >> 2); -} - -static -inline int convert6To8(int b) { - int c = b & 0x3f; - return (c << 2) | (c >> 4); -} - -static -inline int divideBy255(int d) { - return (d + 128 + (d >> 8)) >> 8; -} - -static -inline int convert8To4(int b) { - int c = b & 0xff; - return divideBy255(c * 15); -} - -static -inline int convert8To5(int b) { - int c = b & 0xff; - return divideBy255(c * 31); -} - -static -inline int convertDiff(int base, int diff) { - return convert5To8((0x1f & base) + kLookup[0x7 & diff]); -} - -static -void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, - etc1_uint32 low, bool second, bool flipped) { - int baseX = 0; - int baseY = 0; - if (second) { - if (flipped) { - baseY = 2; - } else { - baseX = 2; - } - } - for (int i = 0; i < 8; i++) { - int x, y; - if (flipped) { - x = baseX + (i >> 1); - y = baseY + (i & 1); - } else { - x = baseX + (i >> 2); - y = baseY + (i & 3); - } - int k = y + (x * 4); - int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); - int delta = table[offset]; - etc1_byte* q = pOut + 3 * (x + 4 * y); - *q++ = clamp(r + delta); - *q++ = clamp(g + delta); - *q++ = clamp(b + delta); - } -} - -// Input is an ETC1 compressed version of the data. -// Output is a 4 x 4 square of 3-byte pixels in form R, G, B - -void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { - etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; - etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; - int r1, r2, g1, g2, b1, b2; - if (high & 2) { - // differential - int rBase = high >> 27; - int gBase = high >> 19; - int bBase = high >> 11; - r1 = convert5To8(rBase); - r2 = convertDiff(rBase, high >> 24); - g1 = convert5To8(gBase); - g2 = convertDiff(gBase, high >> 16); - b1 = convert5To8(bBase); - b2 = convertDiff(bBase, high >> 8); - } else { - // not differential - r1 = convert4To8(high >> 28); - r2 = convert4To8(high >> 24); - g1 = convert4To8(high >> 20); - g2 = convert4To8(high >> 16); - b1 = convert4To8(high >> 12); - b2 = convert4To8(high >> 8); - } - int tableIndexA = 7 & (high >> 5); - int tableIndexB = 7 & (high >> 2); - const int* tableA = kModifierTable + tableIndexA * 4; - const int* tableB = kModifierTable + tableIndexB * 4; - bool flipped = (high & 1) != 0; - decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); - decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); -} - -typedef struct { - etc1_uint32 high; - etc1_uint32 low; - etc1_uint32 score; // Lower is more accurate -} etc_compressed; - -static -inline void take_best(etc_compressed* a, const etc_compressed* b) { - if (a->score > b->score) { - *a = *b; - } -} - -static -void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, - etc1_byte* pColors, bool flipped, bool second) { - int r = 0; - int g = 0; - int b = 0; - - if (flipped) { - int by = 0; - if (second) { - by = 2; - } - for (int y = 0; y < 2; y++) { - int yy = by + y; - for (int x = 0; x < 4; x++) { - int i = x + 4 * yy; - if (inMask & (1 << i)) { - const etc1_byte* p = pIn + i * 3; - r += *(p++); - g += *(p++); - b += *(p++); - } - } - } - } else { - int bx = 0; - if (second) { - bx = 2; - } - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 2; x++) { - int xx = bx + x; - int i = xx + 4 * y; - if (inMask & (1 << i)) { - const etc1_byte* p = pIn + i * 3; - r += *(p++); - g += *(p++); - b += *(p++); - } - } - } - } - pColors[0] = (etc1_byte)((r + 4) >> 3); - pColors[1] = (etc1_byte)((g + 4) >> 3); - pColors[2] = (etc1_byte)((b + 4) >> 3); -} - -static -inline int square(int x) { - return x * x; -} - -static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, - const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, - const int* pModifierTable) { - etc1_uint32 bestScore = ~0; - int bestIndex = 0; - int pixelR = pIn[0]; - int pixelG = pIn[1]; - int pixelB = pIn[2]; - int r = pBaseColors[0]; - int g = pBaseColors[1]; - int b = pBaseColors[2]; - for (int i = 0; i < 4; i++) { - int modifier = pModifierTable[i]; - int decodedG = clamp(g + modifier); - etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); - if (score >= bestScore) { - continue; - } - int decodedR = clamp(r + modifier); - score += (etc1_uint32) (3 * square(decodedR - pixelR)); - if (score >= bestScore) { - continue; - } - int decodedB = clamp(b + modifier); - score += (etc1_uint32) square(decodedB - pixelB); - if (score < bestScore) { - bestScore = score; - bestIndex = i; - } - } - etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) - << bitIndex; - *pLow |= lowMask; - return bestScore; -} - -static -void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, - etc_compressed* pCompressed, bool flipped, bool second, - const etc1_byte* pBaseColors, const int* pModifierTable) { - int score = pCompressed->score; - if (flipped) { - int by = 0; - if (second) { - by = 2; - } - for (int y = 0; y < 2; y++) { - int yy = by + y; - for (int x = 0; x < 4; x++) { - int i = x + 4 * yy; - if (inMask & (1 << i)) { - score += chooseModifier(pBaseColors, pIn + i * 3, - &pCompressed->low, yy + x * 4, pModifierTable); - } - } - } - } else { - int bx = 0; - if (second) { - bx = 2; - } - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 2; x++) { - int xx = bx + x; - int i = xx + 4 * y; - if (inMask & (1 << i)) { - score += chooseModifier(pBaseColors, pIn + i * 3, - &pCompressed->low, y + xx * 4, pModifierTable); - } - } - } - } - pCompressed->score = score; -} - -static bool inRange4bitSigned(int color) { - return color >= -4 && color <= 3; -} - -static void etc_encodeBaseColors(etc1_byte* pBaseColors, - const etc1_byte* pColors, etc_compressed* pCompressed) { - int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks - bool differential; - { - int r51 = convert8To5(pColors[0]); - int g51 = convert8To5(pColors[1]); - int b51 = convert8To5(pColors[2]); - int r52 = convert8To5(pColors[3]); - int g52 = convert8To5(pColors[4]); - int b52 = convert8To5(pColors[5]); - - r1 = convert5To8(r51); - g1 = convert5To8(g51); - b1 = convert5To8(b51); - - int dr = r52 - r51; - int dg = g52 - g51; - int db = b52 - b51; - - differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) - && inRange4bitSigned(db); - if (differential) { - r2 = convert5To8(r51 + dr); - g2 = convert5To8(g51 + dg); - b2 = convert5To8(b51 + db); - pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) - | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; - } - } - - if (!differential) { - int r41 = convert8To4(pColors[0]); - int g41 = convert8To4(pColors[1]); - int b41 = convert8To4(pColors[2]); - int r42 = convert8To4(pColors[3]); - int g42 = convert8To4(pColors[4]); - int b42 = convert8To4(pColors[5]); - r1 = convert4To8(r41); - g1 = convert4To8(g41); - b1 = convert4To8(b41); - r2 = convert4To8(r42); - g2 = convert4To8(g42); - b2 = convert4To8(b42); - pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 - << 16) | (b41 << 12) | (b42 << 8); - } - pBaseColors[0] = r1; - pBaseColors[1] = g1; - pBaseColors[2] = b1; - pBaseColors[3] = r2; - pBaseColors[4] = g2; - pBaseColors[5] = b2; -} - -static -void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, - const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { - pCompressed->score = ~0; - pCompressed->high = (flipped ? 1 : 0); - pCompressed->low = 0; - - etc1_byte pBaseColors[6]; - - etc_encodeBaseColors(pBaseColors, pColors, pCompressed); - - int originalHigh = pCompressed->high; - - const int* pModifierTable = kModifierTable; - for (int i = 0; i < 8; i++, pModifierTable += 4) { - etc_compressed temp; - temp.score = 0; - temp.high = originalHigh | (i << 5); - temp.low = 0; - etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, - pBaseColors, pModifierTable); - take_best(pCompressed, &temp); - } - pModifierTable = kModifierTable; - etc_compressed firstHalf = *pCompressed; - for (int i = 0; i < 8; i++, pModifierTable += 4) { - etc_compressed temp; - temp.score = firstHalf.score; - temp.high = firstHalf.high | (i << 2); - temp.low = firstHalf.low; - etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, - pBaseColors + 3, pModifierTable); - if (i == 0) { - *pCompressed = temp; - } else { - take_best(pCompressed, &temp); - } - } -} - -static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { - pOut[0] = (etc1_byte)(d >> 24); - pOut[1] = (etc1_byte)(d >> 16); - pOut[2] = (etc1_byte)(d >> 8); - pOut[3] = (etc1_byte) d; -} - -// Input is a 4 x 4 square of 3-byte pixels in form R, G, B -// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) -// pixel is valid or not. Invalid pixel color values are ignored when compressing. -// Output is an ETC1 compressed version of the data. - -void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, - etc1_byte* pOut) { - etc1_byte colors[6]; - etc1_byte flippedColors[6]; - etc_average_colors_subblock(pIn, inMask, colors, false, false); - etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); - etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); - etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); - - etc_compressed a, b; - etc_encode_block_helper(pIn, inMask, colors, &a, false); - etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); - take_best(&a, &b); - writeBigEndian(pOut, a.high); - writeBigEndian(pOut + 4, a.low); -} - -// Return the size of the encoded image data (does not include size of PKM header). - -etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { - return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; -} - -// Encode an entire image. -// pIn - pointer to the image data. Formatted such that the Red component of -// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; -// pOut - pointer to encoded data. Must be large enough to store entire encoded image. - -int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, - etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { - if (pixelSize < 2 || pixelSize > 3) { - return -1; - } - static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; - static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, - 0xffff }; - etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; - etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; - - etc1_uint32 encodedWidth = (width + 3) & ~3; - etc1_uint32 encodedHeight = (height + 3) & ~3; - - for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { - etc1_uint32 yEnd = height - y; - if (yEnd > 4) { - yEnd = 4; - } - int ymask = kYMask[yEnd]; - for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { - etc1_uint32 xEnd = width - x; - if (xEnd > 4) { - xEnd = 4; - } - int mask = ymask & kXMask[xEnd]; - for (etc1_uint32 cy = 0; cy < yEnd; cy++) { - etc1_byte* q = block + (cy * 4) * 3; - const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); - if (pixelSize == 3) { - memcpy(q, p, xEnd * 3); - } else { - for (etc1_uint32 cx = 0; cx < xEnd; cx++) { - int pixel = (p[1] << 8) | p[0]; - *q++ = convert5To8(pixel >> 11); - *q++ = convert6To8(pixel >> 5); - *q++ = convert5To8(pixel); - p += pixelSize; - } - } - } - etc1_encode_block(block, mask, encoded); - memcpy(pOut, encoded, sizeof(encoded)); - pOut += sizeof(encoded); - } - } - return 0; -} - -// Decode an entire image. -// pIn - pointer to encoded data. -// pOut - pointer to the image data. Will be written such that the Red component of -// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be -// large enough to store entire image. - - -int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, - etc1_uint32 width, etc1_uint32 height, - etc1_uint32 pixelSize, etc1_uint32 stride) { - if (pixelSize < 2 || pixelSize > 3) { - return -1; - } - etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; - - etc1_uint32 encodedWidth = (width + 3) & ~3; - etc1_uint32 encodedHeight = (height + 3) & ~3; - - for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { - etc1_uint32 yEnd = height - y; - if (yEnd > 4) { - yEnd = 4; - } - for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { - etc1_uint32 xEnd = width - x; - if (xEnd > 4) { - xEnd = 4; - } - etc1_decode_block(pIn, block); - pIn += ETC1_ENCODED_BLOCK_SIZE; - for (etc1_uint32 cy = 0; cy < yEnd; cy++) { - const etc1_byte* q = block + (cy * 4) * 3; - etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); - if (pixelSize == 3) { - memcpy(p, q, xEnd * 3); - } else { - for (etc1_uint32 cx = 0; cx < xEnd; cx++) { - etc1_byte r = *q++; - etc1_byte g = *q++; - etc1_byte b = *q++; - etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); - *p++ = (etc1_byte) pixel; - *p++ = (etc1_byte) (pixel >> 8); - } - } - } - } - } - return 0; -} - -static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; - -static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; -static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; -static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; -static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; -static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; - -static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; - -static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { - pOut[0] = (etc1_byte) (data >> 8); - pOut[1] = (etc1_byte) data; -} - -static etc1_uint32 readBEUint16(const etc1_byte* pIn) { - return (pIn[0] << 8) | pIn[1]; -} - -// Format a PKM header - -void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { - memcpy(pHeader, kMagic, sizeof(kMagic)); - etc1_uint32 encodedWidth = (width + 3) & ~3; - etc1_uint32 encodedHeight = (height + 3) & ~3; - writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); - writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); - writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); - writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); - writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); -} - -// Check if a PKM header is correctly formatted. - -etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { - if (memcmp(pHeader, kMagic, sizeof(kMagic))) { - return false; - } - etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); - etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); - etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); - etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); - etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); - return format == ETC1_RGB_NO_MIPMAPS && - encodedWidth >= width && encodedWidth - width < 4 && - encodedHeight >= height && encodedHeight - height < 4; -} - -// Read the image width from a PKM header - -etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { - return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); -} - -// Read the image height from a PKM header - -etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ - return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); -} diff --git a/external/etc1/etc1.h b/external/etc1/etc1.h deleted file mode 100644 index 0d389052b7..0000000000 --- a/external/etc1/etc1.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef __etc1_h__ -#define __etc1_h__ - -#define ETC1_ENCODED_BLOCK_SIZE 8 -#define ETC1_DECODED_BLOCK_SIZE 48 - -#ifndef ETC1_RGB8_OES -#define ETC1_RGB8_OES 0x8D64 -#endif - -typedef unsigned char etc1_byte; -typedef int etc1_bool; -typedef unsigned int etc1_uint32; - -#ifdef __cplusplus -extern "C" { -#endif - -// Encode a block of pixels. -// -// pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a -// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R -// value of pixel (x, y). -// -// validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether -// the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing. -// -// pOut is an ETC1 compressed version of the data. - -void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut); - -// Decode a block of pixels. -// -// pIn is an ETC1 compressed version of the data. -// -// pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a -// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R -// value of pixel (x, y). - -void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut); - -// Return the size of the encoded image data (does not include size of PKM header). - -etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height); - -// Encode an entire image. -// pIn - pointer to the image data. Formatted such that -// pixel (x,y) is at pIn + pixelSize * x + stride * y; -// pOut - pointer to encoded data. Must be large enough to store entire encoded image. -// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. -// returns non-zero if there is an error. - -int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, - etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut); - -// Decode an entire image. -// pIn - pointer to encoded data. -// pOut - pointer to the image data. Will be written such that -// pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be -// large enough to store entire image. -// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. -// returns non-zero if there is an error. - -int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, - etc1_uint32 width, etc1_uint32 height, - etc1_uint32 pixelSize, etc1_uint32 stride); - -// Size of a PKM header, in bytes. - -#define ETC_PKM_HEADER_SIZE 16 - -// Format a PKM header - -void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height); - -// Check if a PKM header is correctly formatted. - -etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader); - -// Read the image width from a PKM header - -etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader); - -// Read the image height from a PKM header - -etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/s3tc/s3tc.cpp b/external/s3tc/s3tc.cpp deleted file mode 100644 index e7869df631..0000000000 --- a/external/s3tc/s3tc.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "s3tc.h" - -//Decode S3TC encode block to 4x4 RGB32 pixels -static void s3tc_decode_block(uint8_t **blockData, - uint32_t *decodeBlockData, - unsigned int stride, - bool oneBitAlphaFlag, - uint64_t alpha, - S3TCDecodeFlag decodeFlag) -{ - unsigned int colorValue0 = 0 , colorValue1 = 0, initAlpha = (!oneBitAlphaFlag * 255u) << 24; - unsigned int rb0 = 0, rb1 = 0, rb2 = 0, rb3 = 0, g0 = 0, g1 = 0, g2 = 0, g3 = 0; - - uint32_t colors[4], pixelsIndex = 0; - - /* load the two color values*/ - memcpy((void *)&colorValue0, *blockData, 2); - (*blockData) += 2; - - memcpy((void *)&colorValue1, *blockData, 2); - (*blockData) += 2; - - /* the channel is r5g6b5 , 16 bits */ - rb0 = (colorValue0 << 19 | colorValue0 >> 8) & 0xf800f8; - rb1 = (colorValue1 << 19 | colorValue1 >> 8) & 0xf800f8; - g0 = (colorValue0 << 5) & 0x00fc00; - g1 = (colorValue1 << 5) & 0x00fc00; - g0 += (g0 >> 6) & 0x000300; - g1 += (g1 >> 6) & 0x000300; - - colors[0] = rb0 + g0 + initAlpha; - colors[1] = rb1 + g1 + initAlpha; - - /* interpolate the other two color values */ - if (colorValue0 > colorValue1 || oneBitAlphaFlag) - { - rb2 = (((2*rb0 + rb1) * 21) >> 6) & 0xff00ff; - rb3 = (((2*rb1 + rb0) * 21) >> 6) & 0xff00ff; - g2 = (((2*g0 + g1 ) * 21) >> 6) & 0x00ff00; - g3 = (((2*g1 + g0 ) * 21) >> 6) & 0x00ff00; - colors[3] = rb3 + g3 + initAlpha; - } - else - { - rb2 = ((rb0+rb1) >> 1) & 0xff00ff; - g2 = ((g0 +g1 ) >> 1) & 0x00ff00; - colors[3] = 0 ; - } - colors[2] = rb2 + g2 + initAlpha; - - /*read the pixelsIndex , 2bits per pixel, 4 bytes */ - memcpy((void*)&pixelsIndex, *blockData, 4); - (*blockData) += 4; - - if (S3TCDecodeFlag::DXT5 == decodeFlag) - { - //dxt5 use interpolate alpha - // 8-Alpha block: derive the other six alphas. - // Bit code 000 = alpha0, 001 = alpha1, other are interpolated. - - unsigned int alphaArray[8]; - - alphaArray[0] = (alpha ) & 0xff ; - alphaArray[1] = (alpha >> 8) & 0xff ; - - if (alphaArray[0] >= alphaArray[1]) - { - alphaArray[2] = (alphaArray[0]*6 + alphaArray[1]*1) / 7; - alphaArray[3] = (alphaArray[0]*5 + alphaArray[1]*2) / 7; - alphaArray[4] = (alphaArray[0]*4 + alphaArray[1]*3) / 7; - alphaArray[5] = (alphaArray[0]*3 + alphaArray[1]*4) / 7; - alphaArray[6] = (alphaArray[0]*2 + alphaArray[1]*5) / 7; - alphaArray[7] = (alphaArray[0]*1 + alphaArray[1]*6) / 7; - } - else if (alphaArray[0] < alphaArray[1]) - { - alphaArray[2] = (alphaArray[0]*4 + alphaArray[1]*1) / 5; - alphaArray[3] = (alphaArray[0]*3 + alphaArray[1]*2) / 5; - alphaArray[4] = (alphaArray[0]*2 + alphaArray[1]*3) / 5; - alphaArray[5] = (alphaArray[0]*1 + alphaArray[1]*4) / 5; - alphaArray[6] = 0; - alphaArray[7] = 255; - } - - // read the flowing 48bit indices (16*3) - alpha >>= 16; - - for (int y = 0; y < 4; ++y) - { - for (int x = 0; x < 4; ++x) - { - decodeBlockData[x] = (alphaArray[alpha & 5] << 24) + colors[pixelsIndex & 3]; - pixelsIndex >>= 2; - alpha >>= 3; - } - decodeBlockData += stride; - } - } //if (dxt5 == comFlag) - else - { //dxt1 dxt3 use explicit alpha - for (int y = 0; y < 4; ++y) - { - for (int x = 0; x < 4; ++x) - { - initAlpha = (alpha & 0x0f) << 28; - initAlpha += initAlpha >> 4; - decodeBlockData[x] = initAlpha + colors[pixelsIndex & 3]; - pixelsIndex >>= 2; - alpha >>= 4; - } - decodeBlockData += stride; - } - } -} - -//Decode S3TC encode data to RGB32 -void s3tc_decode(uint8_t *encodeData, //in_data - uint8_t *decodeData, //out_data - const int pixelsWidth, - const int pixelsHeight, - S3TCDecodeFlag decodeFlag) -{ - uint32_t *decodeBlockData = (uint32_t *)decodeData; - for (int block_y = 0; block_y < pixelsHeight / 4; ++block_y, decodeBlockData += 3 * pixelsWidth) //stride = 3*width - { - for(int block_x = 0; block_x < pixelsWidth / 4; ++block_x, decodeBlockData += 4) //skip 4 pixels - { - uint64_t blockAlpha = 0; - - switch (decodeFlag) - { - case S3TCDecodeFlag::DXT1: - { - s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 0, 0LL, S3TCDecodeFlag::DXT1); - } - break; - case S3TCDecodeFlag::DXT3: - { - memcpy((void *)&blockAlpha, encodeData, 8); - encodeData += 8; - s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, S3TCDecodeFlag::DXT3); - } - break; - case S3TCDecodeFlag::DXT5: - { - memcpy((void *)&blockAlpha, encodeData, 8); - encodeData += 8; - s3tc_decode_block(&encodeData, decodeBlockData, pixelsWidth, 1, blockAlpha, S3TCDecodeFlag::DXT5); - } - break; - default: - break; - }//switch - }//for block_x - }//for block_y -} - - diff --git a/external/s3tc/s3tc.h b/external/s3tc/s3tc.h deleted file mode 100644 index a3cf233257..0000000000 --- a/external/s3tc/s3tc.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -#ifndef COCOS2DX_PLATFORM_THIRDPARTY_S3TC_ -#define COCOS2DX_PLATFORM_THIRDPARTY_S3TC_ - -#include "CCStdC.h" - -enum class S3TCDecodeFlag -{ - DXT1 = 1, - DXT3 = 3, - DXT5 = 5, -}; - -//Decode S3TC encode data to RGB32 - void s3tc_decode(uint8_t *encode_data, - uint8_t *decode_data, - const int pixelsWidth, - const int pixelsHeight, - S3TCDecodeFlag decodeFlag - ); - - -#endif /* defined(COCOS2DX_PLATFORM_THIRDPARTY_S3TC_) */ -